From bb3716332321e22537a5015be13e2229fb9b90bc Mon Sep 17 00:00:00 2001 From: Jake Hamby Date: Mon, 23 Aug 2010 18:16:48 -0700 Subject: Allow incoming SMS until internal storage is almost full. Fix for bug 2382830: new incoming SMS should not be rejected when running low on internal phone storage. Testing revealed that the /data partition should have at least 256 KiB available in order to prevent random app crashes (including system apps) due to SQLite transaction failures. With 256 KiB free, the device should safely boot without storage full errors. This takes into account the 36-40 KiB that the YAFFS2 filesystem reports as available even after the partition has been completely filled. I've set the default full threshold to 1 MiB to provide a generous safety margin. For this bug, I changed the DeviceStorageMonitorService demon to send two new hidden notifications for device storage "full" and "not full", when the free space falls below the full threshold (default 1 MiB, but configurable as a system setting), in addition to the existing storage low/okay notifications sent when the storage crosses the threshold of 90% full (also configurable). The SMS code was changed to use these new notifications so that it can accept messages until the data partition has been filled to the maximum safe capacity rather than stopping when it hits 90% full. There should be no negative impact on battery life because the additional check in the storage polling service should be offset by an optimization to cache the free threshold values which were previously being computed every time through the loop. While testing this change, I discovered that SMSDispatcher was being instantiated twice, the first time in GSMPhone/CDMAPhone, and the second time in SimSmsInterfaceManager / RuimSmsInterfaceManager. Changed the code to pass the original SMSDispatcher to the Sim/RuimSmsInterfaceManager constructor. Change-Id: Ie0c6d05294778ab6ee42e0fa01313af96d824c77 --- .../server/DeviceStorageMonitorService.java | 62 ++++++++++++++++++++-- 1 file changed, 58 insertions(+), 4 deletions(-) (limited to 'services') diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java index 4a0df59..0b1a4a3 100644 --- a/services/java/com/android/server/DeviceStorageMonitorService.java +++ b/services/java/com/android/server/DeviceStorageMonitorService.java @@ -69,10 +69,12 @@ class DeviceStorageMonitorService extends Binder { 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 static final int DEFAULT_FULL_THRESHOLD_BYTES = 1024*1024; // 1MB private long mFreeMem; // on /data private long mLastReportedFreeMem; private long mLastReportedFreeMemTime; private boolean mLowMemFlag=false; + private boolean mMemFullFlag=false; private Context mContext; private ContentResolver mContentResolver; private long mTotalMemory; // on /data @@ -87,9 +89,13 @@ class DeviceStorageMonitorService extends Binder { private boolean mClearingCache; private Intent mStorageLowIntent; private Intent mStorageOkIntent; + private Intent mStorageFullIntent; + private Intent mStorageNotFullIntent; private CachePackageDataObserver mClearCacheObserver; private static final int _TRUE = 1; private static final int _FALSE = 0; + private long mMemLowThreshold; + private int mMemFullThreshold; /** * This string is used for ServiceManager access to this class. @@ -103,7 +109,7 @@ class DeviceStorageMonitorService extends Binder { Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { - //dont handle an invalid message + //don't handle an invalid message if (msg.what != DEVICE_MEMORY_WHAT) { Slog.e(TAG, "Will not process invalid message"); return; @@ -184,7 +190,7 @@ class DeviceStorageMonitorService extends Binder { try { if (localLOGV) Slog.i(TAG, "Clearing cache"); IPackageManager.Stub.asInterface(ServiceManager.getService("package")). - freeStorageAndNotify(getMemThreshold(), mClearCacheObserver); + freeStorageAndNotify(mMemLowThreshold, mClearCacheObserver); } catch (RemoteException e) { Slog.w(TAG, "Failed to get handle for PackageManger Exception: "+e); mClearingCache = false; @@ -209,8 +215,7 @@ class DeviceStorageMonitorService extends Binder { if (localLOGV) Slog.v(TAG, "freeMemory="+mFreeMem); //post intent to NotificationManager to display icon if necessary - long memThreshold = getMemThreshold(); - if (mFreeMem < memThreshold) { + if (mFreeMem < mMemLowThreshold) { if (!mLowMemFlag) { if (checkCache) { // See if clearing cache helps @@ -235,6 +240,17 @@ class DeviceStorageMonitorService extends Binder { 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 @@ -264,6 +280,20 @@ class DeviceStorageMonitorService extends Binder { return mTotalMemory*value; } + /* + * just query settings to retrieve the memory full threshold. + * Preferred this over using a ContentObserver since Settings.Secure caches the value + * any way + */ + private int getMemFullThreshold() { + int value = Settings.Secure.getInt( + mContentResolver, + Settings.Secure.SYS_STORAGE_FULL_THRESHOLD_BYTES, + DEFAULT_FULL_THRESHOLD_BYTES); + if(localLOGV) Slog.v(TAG, "Full Threshold Bytes="+value); + return value; + } + /** * Constructor to run service. initializes the disk space threshold value * and posts an empty message to kickstart the process. @@ -283,6 +313,13 @@ class DeviceStorageMonitorService extends Binder { 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 + mMemLowThreshold = getMemThreshold(); + mMemFullThreshold = getMemFullThreshold(); checkMemory(true); } @@ -332,6 +369,23 @@ class DeviceStorageMonitorService extends Binder { mContext.sendBroadcast(mStorageOkIntent); } + /** + * Send a notification when storage is full. + */ + private final void sendFullNotification() { + if(localLOGV) Slog.i(TAG, "Sending memory full notification"); + mContext.sendStickyBroadcast(mStorageFullIntent); + } + + /** + * Cancels memory full notification and sends "not full" intent. + */ + private final void cancelFullNotification() { + if(localLOGV) Slog.i(TAG, "Canceling memory full notification"); + mContext.removeStickyBroadcast(mStorageFullIntent); + mContext.sendBroadcast(mStorageNotFullIntent); + } + public void updateMemory() { int callingUid = getCallingUid(); if(callingUid != Process.SYSTEM_UID) { -- cgit v1.1