DeviceStorageMonitorService.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
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 com.android.server.am.ActivityManagerService;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.Notification;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.NotificationManager;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.PendingIntent;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.IPackageDataObserver;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.IPackageManager;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Process;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ServiceManager;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.StatFs;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings.Gservices;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Config;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.EventLog;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This class implements a service to monitor the amount of disk storage space
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * on the device. If the free storage on device is less than a tunable threshold value
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (default is 10%. this value is a gservices parameter) a low memory notification is
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * displayed to alert the user. If the user clicks on the low memory notification the
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Application Manager application gets launched to let the user free storage space.
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Event log events:
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A low memory event with the free storage on device in bytes  is logged to the event log
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * when the device goes low on storage space.
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The amount of free storage on the device is periodically logged to the event log. The log
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * interval is a gservices parameter with a default value of 12 hours
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * When the free storage differential goes below a threshold(again a gservices parameter with
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a default value of 2MB), the free memory is logged to the event log
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass DeviceStorageMonitorService extends Binder {
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "DeviceStorageMonitorService";
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DEBUG = false;
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DEVICE_MEMORY_WHAT = 1;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MONITOR_INTERVAL = 1; //in minutes
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int LOW_MEMORY_NOTIFICATION_ID = 1;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DEFAULT_FREE_STORAGE_LOG_INTERVAL_IN_MINUTES = 12*60; //in minutes
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int EVENT_LOG_STORAGE_BELOW_THRESHOLD = 2744;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int EVENT_LOG_LOW_STORAGE_NOTIFICATION = 2745;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int EVENT_LOG_FREE_STORAGE_LEFT = 2746;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final long DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD = 2 * 1024 * 1024; // 2MB
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final long DEFAULT_CHECK_INTERVAL = MONITOR_INTERVAL*60*1000;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private long mFreeMem;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private long mLastReportedFreeMem;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private long mLastReportedFreeMemTime;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mLowMemFlag=false;
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Context mContext;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ContentResolver mContentResolver;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int mBlkSize;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    long mTotalMemory;
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    StatFs mFileStats;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String DATA_PATH="/data";
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    long mThreadStartTime = -1;
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean mClearSucceeded = false;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean mClearingCache;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Intent mStorageLowIntent;
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Intent mStorageOkIntent;
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private CachePackageDataObserver mClearCacheObserver;
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int _TRUE = 1;
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int _FALSE = 0;
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This string is used for ServiceManager access to this class.
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final String SERVICE = "devicestoragemonitor";
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    * Handler that checks the amount of disk space on the device and sends a
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    * notification if the device runs low on disk space
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    */
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Handler mHandler = new Handler() {
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //dont handle an invalid message
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (msg.what != DEVICE_MEMORY_WHAT) {
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.e(TAG, "Will not process invalid message");
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            checkMemory(msg.arg1 == _TRUE);
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class CachePackageDataObserver extends IPackageDataObserver.Stub {
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onRemoveCompleted(String packageName, boolean succeeded) {
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClearSucceeded = succeeded;
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClearingCache = false;
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if(localLOGV) Log.i(TAG, " Clear succeeded:"+mClearSucceeded
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    +", mClearingCache:"+mClearingCache+" Forcing memory check");
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            postCheckMemoryMsg(false, 0);
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final void restatDataDir() {
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFileStats.restat(DATA_PATH);
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFreeMem = mFileStats.getAvailableBlocks()*mBlkSize;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Allow freemem to be overridden by debug.freemem for testing
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String debugFreeMem = SystemProperties.get("debug.freemem");
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!"".equals(debugFreeMem)) {
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mFreeMem = Long.parseLong(debugFreeMem);
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Read the log interval from Gservices
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long freeMemLogInterval = Gservices.getLong(mContentResolver,
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Gservices.SYS_FREE_STORAGE_LOG_INTERVAL,
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                DEFAULT_FREE_STORAGE_LOG_INTERVAL_IN_MINUTES)*60*1000;
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //log the amount of free memory in event log
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long currTime = SystemClock.elapsedRealtime();
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if((mLastReportedFreeMemTime == 0) ||
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                (currTime-mLastReportedFreeMemTime) >= freeMemLogInterval) {
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLastReportedFreeMemTime = currTime;
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            EventLog.writeEvent(EVENT_LOG_FREE_STORAGE_LEFT, mFreeMem);
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Read the reporting threshold from Gservices
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long threshold = Gservices.getLong(mContentResolver,
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Gservices.DISK_FREE_CHANGE_REPORTING_THRESHOLD,
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD);
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // If mFree changed significantly log the new value
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long delta = mFreeMem - mLastReportedFreeMem;
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (delta > threshold || delta < -threshold) {
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLastReportedFreeMem = mFreeMem;
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            EventLog.writeEvent(EVENT_LOG_STORAGE_BELOW_THRESHOLD, mFreeMem);
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final void clearCache() {
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mClearCacheObserver == null) {
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Lazy instantiation
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClearCacheObserver = new CachePackageDataObserver();
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mClearingCache = true;
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (localLOGV) Log.i(TAG, "Clearing cache");
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            IPackageManager.Stub.asInterface(ServiceManager.getService("package")).
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    freeStorageAndNotify(getMemThreshold(), mClearCacheObserver);
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (RemoteException e) {
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClearingCache = false;
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mClearSucceeded = false;
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final void checkMemory(boolean checkCache) {
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //if the thread that was started to clear cache is still running do nothing till its
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //finished clearing cache. Ideally this flag could be modified by clearCache
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // and should be accessed via a lock but even if it does this test will fail now and
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //hopefully the next time this flag will be set to the correct value.
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if(mClearingCache) {
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if(localLOGV) Log.i(TAG, "Thread already running just skip");
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //make sure the thread is not hung for too long
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long diffTime = System.currentTimeMillis() - mThreadStartTime;
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if(diffTime > (10*60*1000)) {
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.w(TAG, "Thread that clears cache file seems to run for ever");
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            restatDataDir();
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (localLOGV)  Log.v(TAG, "freeMemory="+mFreeMem);
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //post intent to NotificationManager to display icon if necessary
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long memThreshold = getMemThreshold();
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mFreeMem < memThreshold) {
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!mLowMemFlag) {
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (checkCache) {
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // See if clearing cache helps
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // Note that clearing cache is asynchronous and so we do a
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // memory check again once the cache has been cleared.
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mThreadStartTime = System.currentTimeMillis();
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mClearSucceeded = false;
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        clearCache();
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Log.i(TAG, "Running low on memory. Sending notification");
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sendNotification();
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mLowMemFlag = true;
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (localLOGV) Log.v(TAG, "Running low on memory " +
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            "notification already sent. do nothing");
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mLowMemFlag) {
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.i(TAG, "Memory available. Cancelling notification");
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    cancelNotification();
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mLowMemFlag = false;
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if(localLOGV) Log.i(TAG, "Posting Message again");
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //keep posting messages to itself periodically
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        postCheckMemoryMsg(true, DEFAULT_CHECK_INTERVAL);
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void postCheckMemoryMsg(boolean clearCache, long delay) {
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Remove queued messages
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler.removeMessages(DEVICE_MEMORY_WHAT);
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler.sendMessageDelayed(mHandler.obtainMessage(DEVICE_MEMORY_WHAT,
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                clearCache ?_TRUE : _FALSE, 0),
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                delay);
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * just query settings to retrieve the memory threshold.
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Preferred this over using a ContentObserver since Settings.Gservices caches the value
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * any way
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private long getMemThreshold() {
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int value = Settings.Gservices.getInt(
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              mContentResolver,
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              Settings.Gservices.SYS_STORAGE_THRESHOLD_PERCENTAGE,
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                              DEFAULT_THRESHOLD_PERCENTAGE);
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if(localLOGV) Log.v(TAG, "Threshold Percentage="+value);
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //evaluate threshold value
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mTotalMemory*value;
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    * Constructor to run service. initializes the disk space threshold value
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    * and posts an empty message to kickstart the process.
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    */
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public DeviceStorageMonitorService(Context context) {
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLastReportedFreeMemTime = 0;
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContentResolver = mContext.getContentResolver();
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //create StatFs object
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFileStats = new StatFs(DATA_PATH);
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //initialize block size
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBlkSize = mFileStats.getBlockSize();
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //initialize total storage on device
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTotalMemory = (mFileStats.getBlockCount()*mBlkSize)/100;
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStorageLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW);
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStorageOkIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK);
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkMemory(true);
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    * This method sends a notification to NotificationManager to display
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    * an error dialog indicating low disk space and launch the Installer
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    * application
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    */
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final void sendNotification() {
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if(localLOGV) Log.i(TAG, "Sending low memory notification");
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //log the event to event log with the amount of free storage(in bytes) left on the device
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        EventLog.writeEvent(EVENT_LOG_LOW_STORAGE_NOTIFICATION, mFreeMem);
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //  Pack up the values and broadcast them to everyone
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Intent lowMemIntent = new Intent(Intent.ACTION_MANAGE_PACKAGE_STORAGE);
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lowMemIntent.putExtra("memory", mFreeMem);
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        lowMemIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        NotificationManager mNotificationMgr =
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                (NotificationManager)mContext.getSystemService(
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Context.NOTIFICATION_SERVICE);
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CharSequence title = mContext.getText(
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                com.android.internal.R.string.low_internal_storage_view_title);
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CharSequence details = mContext.getText(
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                com.android.internal.R.string.low_internal_storage_view_text);
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PendingIntent intent = PendingIntent.getActivity(mContext, 0,  lowMemIntent, 0);
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Notification notification = new Notification();
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        notification.icon = com.android.internal.R.drawable.stat_notify_disk_full;
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        notification.tickerText = title;
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        notification.flags |= Notification.FLAG_NO_CLEAR;
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        notification.setLatestEventInfo(mContext, title, details, intent);
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mNotificationMgr.notify(LOW_MEMORY_NOTIFICATION_ID, notification);
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.sendStickyBroadcast(mStorageLowIntent);
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Cancels low storage notification and sends OK intent.
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final void cancelNotification() {
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if(localLOGV) Log.i(TAG, "Canceling low memory notification");
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        NotificationManager mNotificationMgr =
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                (NotificationManager)mContext.getSystemService(
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Context.NOTIFICATION_SERVICE);
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        //cancel notification since memory has been freed
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mNotificationMgr.cancel(LOW_MEMORY_NOTIFICATION_ID);
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.removeStickyBroadcast(mStorageLowIntent);
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext.sendBroadcast(mStorageOkIntent);
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void updateMemory() {
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int callingUid = getCallingUid();
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if(callingUid != Process.SYSTEM_UID) {
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // force an early check
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        postCheckMemoryMsg(true, 0);
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
315