diff options
Diffstat (limited to 'services/java/com/android/server/DeviceStorageMonitorService.java')
| -rw-r--r-- | services/java/com/android/server/DeviceStorageMonitorService.java | 491 |
1 files changed, 0 insertions, 491 deletions
diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java deleted file mode 100644 index 016c561077dc..000000000000 --- a/services/java/com/android/server/DeviceStorageMonitorService.java +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Copyright (C) 2007-2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.pm.IPackageDataObserver; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; -import android.os.Binder; -import android.os.Environment; -import android.os.FileObserver; -import android.os.Handler; -import android.os.Message; -import android.os.Process; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.StatFs; -import android.os.SystemClock; -import android.os.SystemProperties; -import android.os.UserHandle; -import android.os.storage.StorageManager; -import android.provider.Settings; -import android.text.format.Formatter; -import android.util.EventLog; -import android.util.Slog; -import android.util.TimeUtils; - -import java.io.File; -import java.io.FileDescriptor; -import java.io.PrintWriter; - -/** - * This class implements a service to monitor the amount of disk - * storage space on the device. If the free storage on device is less - * than a tunable threshold value (a secure settings parameter; - * default 10%) a low memory notification is displayed to alert the - * user. If the user clicks on the low memory notification the - * Application Manager application gets launched to let the user free - * storage space. - * - * Event log events: A low memory event with the free storage on - * device in bytes is logged to the event log when the device goes low - * on storage space. The amount of free storage on the device is - * periodically logged to the event log. The log interval is a secure - * settings parameter with a default value of 12 hours. When the free - * storage differential goes below a threshold (again a secure - * settings parameter with a default value of 2MB), the free memory is - * logged to the event log. - */ -public class DeviceStorageMonitorService extends Binder { - private static final String TAG = "DeviceStorageMonitorService"; - - private static final boolean DEBUG = false; - private static final boolean localLOGV = false; - - private static final int DEVICE_MEMORY_WHAT = 1; - private static final int MONITOR_INTERVAL = 1; //in minutes - private static final int LOW_MEMORY_NOTIFICATION_ID = 1; - - private static final int DEFAULT_FREE_STORAGE_LOG_INTERVAL_IN_MINUTES = 12*60; //in minutes - private static final long DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD = 2 * 1024 * 1024; // 2MB - private static final long DEFAULT_CHECK_INTERVAL = MONITOR_INTERVAL*60*1000; - - private long mFreeMem; // on /data - private long mFreeMemAfterLastCacheClear; // on /data - private long mLastReportedFreeMem; - private long mLastReportedFreeMemTime; - private boolean mLowMemFlag=false; - private boolean mMemFullFlag=false; - private Context mContext; - private ContentResolver mResolver; - private long mTotalMemory; // on /data - private StatFs mDataFileStats; - private StatFs mSystemFileStats; - private StatFs mCacheFileStats; - - private static final File DATA_PATH = Environment.getDataDirectory(); - private static final File SYSTEM_PATH = Environment.getRootDirectory(); - private static final File CACHE_PATH = Environment.getDownloadCacheDirectory(); - - private long mThreadStartTime = -1; - private boolean mClearSucceeded = false; - private boolean mClearingCache; - private Intent mStorageLowIntent; - private Intent mStorageOkIntent; - private Intent mStorageFullIntent; - private Intent mStorageNotFullIntent; - private CachePackageDataObserver mClearCacheObserver; - private final CacheFileDeletedObserver mCacheFileDeletedObserver; - private static final int _TRUE = 1; - private static final int _FALSE = 0; - // This is the raw threshold that has been set at which we consider - // storage to be low. - private long mMemLowThreshold; - // This is the threshold at which we start trying to flush caches - // to get below the low threshold limit. It is less than the low - // threshold; we will allow storage to get a bit beyond the limit - // before flushing and checking if we are actually low. - private long mMemCacheStartTrimThreshold; - // This is the threshold that we try to get to when deleting cache - // files. This is greater than the low threshold so that we will flush - // more files than absolutely needed, to reduce the frequency that - // flushing takes place. - private long mMemCacheTrimToThreshold; - private long mMemFullThreshold; - - /** - * This string is used for ServiceManager access to this class. - */ - public static final String SERVICE = "devicestoragemonitor"; - - /** - * Handler that checks the amount of disk space on the device and sends a - * notification if the device runs low on disk space - */ - Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - //don't handle an invalid message - if (msg.what != DEVICE_MEMORY_WHAT) { - Slog.e(TAG, "Will not process invalid message"); - return; - } - checkMemory(msg.arg1 == _TRUE); - } - }; - - class CachePackageDataObserver extends IPackageDataObserver.Stub { - public void onRemoveCompleted(String packageName, boolean succeeded) { - mClearSucceeded = succeeded; - mClearingCache = false; - if(localLOGV) Slog.i(TAG, " Clear succeeded:"+mClearSucceeded - +", mClearingCache:"+mClearingCache+" Forcing memory check"); - postCheckMemoryMsg(false, 0); - } - } - - private final void restatDataDir() { - try { - mDataFileStats.restat(DATA_PATH.getAbsolutePath()); - mFreeMem = (long) mDataFileStats.getAvailableBlocks() * - mDataFileStats.getBlockSize(); - } catch (IllegalArgumentException e) { - // use the old value of mFreeMem - } - // Allow freemem to be overridden by debug.freemem for testing - String debugFreeMem = SystemProperties.get("debug.freemem"); - if (!"".equals(debugFreeMem)) { - mFreeMem = Long.parseLong(debugFreeMem); - } - // Read the log interval from secure settings - long freeMemLogInterval = Settings.Global.getLong(mResolver, - Settings.Global.SYS_FREE_STORAGE_LOG_INTERVAL, - DEFAULT_FREE_STORAGE_LOG_INTERVAL_IN_MINUTES)*60*1000; - //log the amount of free memory in event log - long currTime = SystemClock.elapsedRealtime(); - if((mLastReportedFreeMemTime == 0) || - (currTime-mLastReportedFreeMemTime) >= freeMemLogInterval) { - mLastReportedFreeMemTime = currTime; - long mFreeSystem = -1, mFreeCache = -1; - try { - mSystemFileStats.restat(SYSTEM_PATH.getAbsolutePath()); - mFreeSystem = (long) mSystemFileStats.getAvailableBlocks() * - mSystemFileStats.getBlockSize(); - } catch (IllegalArgumentException e) { - // ignore; report -1 - } - try { - mCacheFileStats.restat(CACHE_PATH.getAbsolutePath()); - mFreeCache = (long) mCacheFileStats.getAvailableBlocks() * - mCacheFileStats.getBlockSize(); - } catch (IllegalArgumentException e) { - // ignore; report -1 - } - EventLog.writeEvent(EventLogTags.FREE_STORAGE_LEFT, - mFreeMem, mFreeSystem, mFreeCache); - } - // Read the reporting threshold from secure settings - long threshold = Settings.Global.getLong(mResolver, - Settings.Global.DISK_FREE_CHANGE_REPORTING_THRESHOLD, - DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD); - // If mFree changed significantly log the new value - long delta = mFreeMem - mLastReportedFreeMem; - if (delta > threshold || delta < -threshold) { - mLastReportedFreeMem = mFreeMem; - EventLog.writeEvent(EventLogTags.FREE_STORAGE_CHANGED, mFreeMem); - } - } - - private final void clearCache() { - if (mClearCacheObserver == null) { - // Lazy instantiation - mClearCacheObserver = new CachePackageDataObserver(); - } - mClearingCache = true; - try { - if (localLOGV) Slog.i(TAG, "Clearing cache"); - IPackageManager.Stub.asInterface(ServiceManager.getService("package")). - freeStorageAndNotify(mMemCacheTrimToThreshold, mClearCacheObserver); - } catch (RemoteException e) { - Slog.w(TAG, "Failed to get handle for PackageManger Exception: "+e); - mClearingCache = false; - mClearSucceeded = false; - } - } - - private final void checkMemory(boolean checkCache) { - //if the thread that was started to clear cache is still running do nothing till its - //finished clearing cache. Ideally this flag could be modified by clearCache - // and should be accessed via a lock but even if it does this test will fail now and - //hopefully the next time this flag will be set to the correct value. - if(mClearingCache) { - if(localLOGV) Slog.i(TAG, "Thread already running just skip"); - //make sure the thread is not hung for too long - long diffTime = System.currentTimeMillis() - mThreadStartTime; - if(diffTime > (10*60*1000)) { - Slog.w(TAG, "Thread that clears cache file seems to run for ever"); - } - } else { - restatDataDir(); - if (localLOGV) Slog.v(TAG, "freeMemory="+mFreeMem); - - //post intent to NotificationManager to display icon if necessary - if (mFreeMem < mMemLowThreshold) { - if (checkCache) { - // We are allowed to clear cache files at this point to - // try to get down below the limit, because this is not - // the initial call after a cache clear has been attempted. - // In this case we will try a cache clear if our free - // space has gone below the cache clear limit. - if (mFreeMem < mMemCacheStartTrimThreshold) { - // We only clear the cache if the free storage has changed - // a significant amount since the last time. - if ((mFreeMemAfterLastCacheClear-mFreeMem) - >= ((mMemLowThreshold-mMemCacheStartTrimThreshold)/4)) { - // See if clearing cache helps - // Note that clearing cache is asynchronous and so we do a - // memory check again once the cache has been cleared. - mThreadStartTime = System.currentTimeMillis(); - mClearSucceeded = false; - clearCache(); - } - } - } else { - // This is a call from after clearing the cache. Note - // the amount of free storage at this point. - mFreeMemAfterLastCacheClear = mFreeMem; - if (!mLowMemFlag) { - // We tried to clear the cache, but that didn't get us - // below the low storage limit. Tell the user. - Slog.i(TAG, "Running low on memory. Sending notification"); - sendNotification(); - mLowMemFlag = true; - } else { - if (localLOGV) Slog.v(TAG, "Running low on memory " + - "notification already sent. do nothing"); - } - } - } else { - mFreeMemAfterLastCacheClear = mFreeMem; - if (mLowMemFlag) { - Slog.i(TAG, "Memory available. Cancelling notification"); - cancelNotification(); - mLowMemFlag = false; - } - } - if (mFreeMem < mMemFullThreshold) { - if (!mMemFullFlag) { - sendFullNotification(); - mMemFullFlag = true; - } - } else { - if (mMemFullFlag) { - cancelFullNotification(); - mMemFullFlag = false; - } - } - } - if(localLOGV) Slog.i(TAG, "Posting Message again"); - //keep posting messages to itself periodically - postCheckMemoryMsg(true, DEFAULT_CHECK_INTERVAL); - } - - private void postCheckMemoryMsg(boolean clearCache, long delay) { - // Remove queued messages - mHandler.removeMessages(DEVICE_MEMORY_WHAT); - mHandler.sendMessageDelayed(mHandler.obtainMessage(DEVICE_MEMORY_WHAT, - clearCache ?_TRUE : _FALSE, 0), - delay); - } - - /** - * Constructor to run service. initializes the disk space threshold value - * and posts an empty message to kickstart the process. - */ - public DeviceStorageMonitorService(Context context) { - mLastReportedFreeMemTime = 0; - mContext = context; - mResolver = mContext.getContentResolver(); - //create StatFs object - mDataFileStats = new StatFs(DATA_PATH.getAbsolutePath()); - mSystemFileStats = new StatFs(SYSTEM_PATH.getAbsolutePath()); - mCacheFileStats = new StatFs(CACHE_PATH.getAbsolutePath()); - //initialize total storage on device - mTotalMemory = (long)mDataFileStats.getBlockCount() * - mDataFileStats.getBlockSize(); - mStorageLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW); - mStorageLowIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - mStorageOkIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK); - mStorageOkIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - mStorageFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_FULL); - mStorageFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - mStorageNotFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_NOT_FULL); - mStorageNotFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - - // cache storage thresholds - final StorageManager sm = StorageManager.from(context); - mMemLowThreshold = sm.getStorageLowBytes(DATA_PATH); - mMemFullThreshold = sm.getStorageFullBytes(DATA_PATH); - - mMemCacheStartTrimThreshold = ((mMemLowThreshold*3)+mMemFullThreshold)/4; - mMemCacheTrimToThreshold = mMemLowThreshold - + ((mMemLowThreshold-mMemCacheStartTrimThreshold)*2); - mFreeMemAfterLastCacheClear = mTotalMemory; - checkMemory(true); - - mCacheFileDeletedObserver = new CacheFileDeletedObserver(); - mCacheFileDeletedObserver.startWatching(); - } - - /** - * This method sends a notification to NotificationManager to display - * an error dialog indicating low disk space and launch the Installer - * application - */ - private final void sendNotification() { - if(localLOGV) Slog.i(TAG, "Sending low memory notification"); - //log the event to event log with the amount of free storage(in bytes) left on the device - EventLog.writeEvent(EventLogTags.LOW_STORAGE, mFreeMem); - // Pack up the values and broadcast them to everyone - Intent lowMemIntent = new Intent(Environment.isExternalStorageEmulated() - ? Settings.ACTION_INTERNAL_STORAGE_SETTINGS - : Intent.ACTION_MANAGE_PACKAGE_STORAGE); - lowMemIntent.putExtra("memory", mFreeMem); - lowMemIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - NotificationManager mNotificationMgr = - (NotificationManager)mContext.getSystemService( - Context.NOTIFICATION_SERVICE); - CharSequence title = mContext.getText( - com.android.internal.R.string.low_internal_storage_view_title); - CharSequence details = mContext.getText( - com.android.internal.R.string.low_internal_storage_view_text); - PendingIntent intent = PendingIntent.getActivityAsUser(mContext, 0, lowMemIntent, 0, - null, UserHandle.CURRENT); - Notification notification = new Notification(); - notification.icon = com.android.internal.R.drawable.stat_notify_disk_full; - notification.tickerText = title; - notification.flags |= Notification.FLAG_NO_CLEAR; - notification.setLatestEventInfo(mContext, title, details, intent); - mNotificationMgr.notifyAsUser(null, LOW_MEMORY_NOTIFICATION_ID, notification, - UserHandle.ALL); - mContext.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL); - } - - /** - * Cancels low storage notification and sends OK intent. - */ - private final void cancelNotification() { - if(localLOGV) Slog.i(TAG, "Canceling low memory notification"); - NotificationManager mNotificationMgr = - (NotificationManager)mContext.getSystemService( - Context.NOTIFICATION_SERVICE); - //cancel notification since memory has been freed - mNotificationMgr.cancelAsUser(null, LOW_MEMORY_NOTIFICATION_ID, UserHandle.ALL); - - mContext.removeStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL); - mContext.sendBroadcastAsUser(mStorageOkIntent, UserHandle.ALL); - } - - /** - * Send a notification when storage is full. - */ - private final void sendFullNotification() { - if(localLOGV) Slog.i(TAG, "Sending memory full notification"); - mContext.sendStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL); - } - - /** - * Cancels memory full notification and sends "not full" intent. - */ - private final void cancelFullNotification() { - if(localLOGV) Slog.i(TAG, "Canceling memory full notification"); - mContext.removeStickyBroadcastAsUser(mStorageFullIntent, UserHandle.ALL); - mContext.sendBroadcastAsUser(mStorageNotFullIntent, UserHandle.ALL); - } - - public void updateMemory() { - int callingUid = getCallingUid(); - if(callingUid != Process.SYSTEM_UID) { - return; - } - // force an early check - postCheckMemoryMsg(true, 0); - } - - /** - * Callable from other things in the system service to obtain the low memory - * threshold. - * - * @return low memory threshold in bytes - */ - public long getMemoryLowThreshold() { - return mMemLowThreshold; - } - - /** - * Callable from other things in the system process to check whether memory - * is low. - * - * @return true is memory is low - */ - public boolean isMemoryLow() { - return mLowMemFlag; - } - - public static class CacheFileDeletedObserver extends FileObserver { - public CacheFileDeletedObserver() { - super(Environment.getDownloadCacheDirectory().getAbsolutePath(), FileObserver.DELETE); - } - - @Override - public void onEvent(int event, String path) { - EventLogTags.writeCacheFileDeleted(path); - } - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - - pw.println("Permission Denial: can't dump " + SERVICE + " from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } - - pw.println("Current DeviceStorageMonitor state:"); - pw.print(" mFreeMem="); pw.print(Formatter.formatFileSize(mContext, mFreeMem)); - pw.print(" mTotalMemory="); - pw.println(Formatter.formatFileSize(mContext, mTotalMemory)); - pw.print(" mFreeMemAfterLastCacheClear="); - pw.println(Formatter.formatFileSize(mContext, mFreeMemAfterLastCacheClear)); - pw.print(" mLastReportedFreeMem="); - pw.print(Formatter.formatFileSize(mContext, mLastReportedFreeMem)); - pw.print(" mLastReportedFreeMemTime="); - TimeUtils.formatDuration(mLastReportedFreeMemTime, SystemClock.elapsedRealtime(), pw); - pw.println(); - pw.print(" mLowMemFlag="); pw.print(mLowMemFlag); - pw.print(" mMemFullFlag="); pw.println(mMemFullFlag); - pw.print(" mClearSucceeded="); pw.print(mClearSucceeded); - pw.print(" mClearingCache="); pw.println(mClearingCache); - pw.print(" mMemLowThreshold="); - pw.print(Formatter.formatFileSize(mContext, mMemLowThreshold)); - pw.print(" mMemFullThreshold="); - pw.println(Formatter.formatFileSize(mContext, mMemFullThreshold)); - pw.print(" mMemCacheStartTrimThreshold="); - pw.print(Formatter.formatFileSize(mContext, mMemCacheStartTrimThreshold)); - pw.print(" mMemCacheTrimToThreshold="); - pw.println(Formatter.formatFileSize(mContext, mMemCacheTrimToThreshold)); - } -} |
