From 3161795b2353171bb0636fb3ea6dab7dec80a4f4 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Wed, 7 Oct 2009 15:14:03 -0700 Subject: [PATCH 1/5] when logging free space on /data, log /system and /cache as well Report space free on system and cache so we can estimate bad block statistics for devices in the field. --- .../server/DeviceStorageMonitorService.java | 104 +++++++++++------- 1 file changed, 65 insertions(+), 39 deletions(-) diff --git a/services/java/com/android/server/DeviceStorageMonitorService.java b/services/java/com/android/server/DeviceStorageMonitorService.java index 52e09ca260a55..57af02953415d 100644 --- a/services/java/com/android/server/DeviceStorageMonitorService.java +++ b/services/java/com/android/server/DeviceStorageMonitorService.java @@ -43,8 +43,8 @@ import android.provider.Settings; /** * 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 - * (default is 10%. this value is a gservices parameter) a low memory notification is - * displayed to alert the user. If the user clicks on the low memory notification the + * (default is 10%. this value is a gservices parameter) 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 @@ -68,32 +68,35 @@ class DeviceStorageMonitorService extends Binder { private static final int EVENT_LOG_FREE_STORAGE_LEFT = 2746; 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; + private long mFreeMem; // on /data private long mLastReportedFreeMem; private long mLastReportedFreeMemTime; private boolean mLowMemFlag=false; private Context mContext; private ContentResolver mContentResolver; - long mBlkSize; - long mTotalMemory; - StatFs mFileStats; - private static final String DATA_PATH="/data"; - long mThreadStartTime = -1; - boolean mClearSucceeded = false; - boolean mClearingCache; + private long mTotalMemory; // on /data + private StatFs mDataFileStats; + private StatFs mSystemFileStats; + private StatFs mCacheFileStats; + private static final String DATA_PATH = "/data"; + private static final String SYSTEM_PATH = "/system"; + private static final String CACHE_PATH = "/cache"; + private long mThreadStartTime = -1; + private boolean mClearSucceeded = false; + private boolean mClearingCache; private Intent mStorageLowIntent; private Intent mStorageOkIntent; private CachePackageDataObserver mClearCacheObserver; private static final int _TRUE = 1; private static final int _FALSE = 0; - + /** * This string is used for ServiceManager access to this class. */ static final String SERVICE = "devicestoragemonitor"; - + /** - * Handler that checks the amount of disk space on the device and sends a + * 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() { @@ -107,7 +110,7 @@ class DeviceStorageMonitorService extends Binder { checkMemory(msg.arg1 == _TRUE); } }; - + class CachePackageDataObserver extends IPackageDataObserver.Stub { public void onRemoveCompleted(String packageName, boolean succeeded) { mClearSucceeded = succeeded; @@ -115,12 +118,17 @@ class DeviceStorageMonitorService extends Binder { if(localLOGV) Log.i(TAG, " Clear succeeded:"+mClearSucceeded +", mClearingCache:"+mClearingCache+" Forcing memory check"); postCheckMemoryMsg(false, 0); - } + } } - + private final void restatDataDir() { - mFileStats.restat(DATA_PATH); - mFreeMem = mFileStats.getAvailableBlocks()*mBlkSize; + try { + mDataFileStats.restat(DATA_PATH); + 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)) { @@ -132,10 +140,27 @@ class DeviceStorageMonitorService extends Binder { 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) { + if((mLastReportedFreeMemTime == 0) || + (currTime-mLastReportedFreeMemTime) >= freeMemLogInterval) { mLastReportedFreeMemTime = currTime; - EventLog.writeEvent(EVENT_LOG_FREE_STORAGE_LEFT, mFreeMem); + long mFreeSystem = -1, mFreeCache = -1; + try { + mSystemFileStats.restat(SYSTEM_PATH); + mFreeSystem = (long) mSystemFileStats.getAvailableBlocks() * + mSystemFileStats.getBlockSize(); + } catch (IllegalArgumentException e) { + // ignore; report -1 + } + try { + mCacheFileStats.restat(CACHE_PATH); + mFreeCache = (long) mCacheFileStats.getAvailableBlocks() * + mCacheFileStats.getBlockSize(); + } catch (IllegalArgumentException e) { + // ignore; report -1 + } + mCacheFileStats.restat(CACHE_PATH); + EventLog.writeEvent(EVENT_LOG_FREE_STORAGE_LEFT, + mFreeMem, mFreeSystem, mFreeCache); } // Read the reporting threshold from Gservices long threshold = Gservices.getLong(mContentResolver, @@ -148,7 +173,7 @@ class DeviceStorageMonitorService extends Binder { EventLog.writeEvent(EVENT_LOG_STORAGE_BELOW_THRESHOLD, mFreeMem); } } - + private final void clearCache() { if (mClearCacheObserver == null) { // Lazy instantiation @@ -165,10 +190,10 @@ class DeviceStorageMonitorService extends Binder { 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 + //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) { @@ -177,11 +202,11 @@ class DeviceStorageMonitorService extends Binder { long diffTime = System.currentTimeMillis() - mThreadStartTime; if(diffTime > (10*60*1000)) { Log.w(TAG, "Thread that clears cache file seems to run for ever"); - } + } } else { restatDataDir(); if (localLOGV) Log.v(TAG, "freeMemory="+mFreeMem); - + //post intent to NotificationManager to display icon if necessary long memThreshold = getMemThreshold(); if (mFreeMem < memThreshold) { @@ -214,7 +239,7 @@ class DeviceStorageMonitorService extends Binder { //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); @@ -222,16 +247,16 @@ class DeviceStorageMonitorService extends Binder { clearCache ?_TRUE : _FALSE, 0), delay); } - + /* - * just query settings to retrieve the memory threshold. + * just query settings to retrieve the memory threshold. * Preferred this over using a ContentObserver since Settings.Gservices caches the value * any way */ private long getMemThreshold() { int value = Settings.Gservices.getInt( - mContentResolver, - Settings.Gservices.SYS_STORAGE_THRESHOLD_PERCENTAGE, + mContentResolver, + Settings.Gservices.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE); if(localLOGV) Log.v(TAG, "Threshold Percentage="+value); //evaluate threshold value @@ -247,16 +272,17 @@ class DeviceStorageMonitorService extends Binder { mContext = context; mContentResolver = mContext.getContentResolver(); //create StatFs object - mFileStats = new StatFs(DATA_PATH); - //initialize block size - mBlkSize = mFileStats.getBlockSize(); + mDataFileStats = new StatFs(DATA_PATH); + mSystemFileStats = new StatFs(SYSTEM_PATH); + mCacheFileStats = new StatFs(CACHE_PATH); //initialize total storage on device - mTotalMemory = ((long)mFileStats.getBlockCount()*mBlkSize)/100L; + mTotalMemory = ((long)mDataFileStats.getBlockCount() * + mDataFileStats.getBlockSize())/100L; mStorageLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW); mStorageOkIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK); checkMemory(true); } - + /** * This method sends a notification to NotificationManager to display @@ -271,7 +297,7 @@ class DeviceStorageMonitorService extends Binder { Intent lowMemIntent = new Intent(Intent.ACTION_MANAGE_PACKAGE_STORAGE); lowMemIntent.putExtra("memory", mFreeMem); lowMemIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - NotificationManager mNotificationMgr = + NotificationManager mNotificationMgr = (NotificationManager)mContext.getSystemService( Context.NOTIFICATION_SERVICE); CharSequence title = mContext.getText( @@ -302,7 +328,7 @@ class DeviceStorageMonitorService extends Binder { mContext.removeStickyBroadcast(mStorageLowIntent); mContext.sendBroadcast(mStorageOkIntent); } - + public void updateMemory() { int callingUid = getCallingUid(); if(callingUid != Process.SYSTEM_UID) { From 46b2df153fccf7f918ee5d7d747c208bdd2d55f4 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Wed, 7 Oct 2009 17:58:29 -0700 Subject: [PATCH 2/5] fix [2164183] sometimes device just wants to stay asleep When switching rapidily orientation back and forth, surfaces end-up acquiring the freeze-lock when the first orientation change happens, but never release it because by the time the 2nd orientation change comes in, the surface size is back to its original size and doesn't appear to have resized. we now always release the freeze-lock when we receive a buffer of the expected size. --- libs/surfaceflinger/Layer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp index 2a3e6677e7451..7fd5434d05230 100644 --- a/libs/surfaceflinger/Layer.cpp +++ b/libs/surfaceflinger/Layer.cpp @@ -454,10 +454,10 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) // recompute visible region recomputeVisibleRegions = true; - - // we now have the correct size, unfreeze the screen - mFreezeLock.clear(); } + + // we now have the correct size, unfreeze the screen + mFreezeLock.clear(); } if (lcblk->getQueuedCount()) { From 0da41a3635180398ae6cbf1ff75575f5dcb6e40b Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 6 Oct 2009 15:58:44 -0700 Subject: [PATCH 3/5] fix [2170283] SurfaceFlinger crashes on OOM. when running out of memory, a null handle is returned but the error code may not be set. In that case we need to return NO_MEMORY instead of NO_ERROR, so that the calling code won't try to dereference the null pointer. --- libs/ui/Surface.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp index 2d83a8c3106de..f51ca7a953c7b 100644 --- a/libs/ui/Surface.cpp +++ b/libs/ui/Surface.cpp @@ -746,6 +746,8 @@ status_t Surface::getBufferLocked(int index, int usage) currentBuffer->setIndex(index); mNeedFullUpdate = true; } + } else { + err = err<0 ? err : NO_MEMORY; } } return err; From bd2197fb0038acd2dc4b17ad3ed3c69cc29dcce2 Mon Sep 17 00:00:00 2001 From: Jason Sams Date: Wed, 7 Oct 2009 18:14:01 -0700 Subject: [PATCH 4/5] Add script to script call support. Add exception to catch out of bound index data when added to TriangleMeshBuilder. --- graphics/java/android/renderscript/SimpleMesh.java | 5 +++++ libs/rs/rsContext.h | 2 +- libs/rs/rsScriptC_Lib.cpp | 10 ++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/graphics/java/android/renderscript/SimpleMesh.java b/graphics/java/android/renderscript/SimpleMesh.java index b422702bbc43b..0ad093e579781 100644 --- a/graphics/java/android/renderscript/SimpleMesh.java +++ b/graphics/java/android/renderscript/SimpleMesh.java @@ -290,6 +290,11 @@ public class SimpleMesh extends BaseObj { } public void addTriangle(int idx1, int idx2, int idx3) { + if((idx1 >= mVtxCount) || (idx1 < 0) || + (idx2 >= mVtxCount) || (idx2 < 0) || + (idx3 >= mVtxCount) || (idx3 < 0)) { + throw new IllegalStateException("Index provided greater than vertex count."); + } if ((mIndexCount + 3) >= mIndexData.length) { short t[] = new short[mIndexData.length * 2]; System.arraycopy(mIndexData, 0, t, 0, mIndexData.length); diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h index b56e7d7f8476a..3570e102d96e8 100644 --- a/libs/rs/rsContext.h +++ b/libs/rs/rsContext.h @@ -99,6 +99,7 @@ public: uint32_t getMessageToClient(void *data, size_t *receiveLen, size_t bufferLen, bool wait); bool sendMessageToClient(void *data, uint32_t cmdID, size_t len, bool waitForSpace); + bool runScript(Script *s, uint32_t launchID); void initToClient(); void deinitToClient(); @@ -212,7 +213,6 @@ private: void initEGL(); - bool runScript(Script *s, uint32_t launchID); bool runRootScript(); static void * threadProc(void *); diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp index 9a962907a1007..436f48b319efd 100644 --- a/libs/rs/rsScriptC_Lib.cpp +++ b/libs/rs/rsScriptC_Lib.cpp @@ -1008,6 +1008,13 @@ static uint32_t SC_toClient(void *data, int cmdID, int len, int waitForSpace) return rsc->sendMessageToClient(data, cmdID, len, waitForSpace != 0); } +static void SC_scriptCall(int scriptID) +{ + GET_TLS(); + rsc->runScript((Script *)scriptID, 0); +} + + ////////////////////////////////////////////////////////////////////////////// // Class implementation ////////////////////////////////////////////////////////////////////////////// @@ -1289,6 +1296,9 @@ ScriptCState::SymbolTable_t ScriptCState::gSyms[] = { { "debugHexI32", (void *)&SC_debugHexI32, "void", "(void *, int)" }, + { "scriptCall", (void *)&SC_scriptCall, + "void", "(int)" }, + { NULL, NULL, NULL, NULL } }; From 2133640028ef53b33a93ecfb593d30c95fed84c6 Mon Sep 17 00:00:00 2001 From: Dave Sparks Date: Wed, 7 Oct 2009 19:18:20 -0700 Subject: [PATCH 5/5] Retry overlay create if it fails. Bug 2153980. Occasionally we see references to the overlay hanging around long enough to cause problems in applications when they tried to destroy the overlay and re-create it. This patch causes the camera HAL to retry the overlay creation call if it fails every 20ms up to 50 times before it gives up. --- camera/libcameraservice/CameraService.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp index 8279914f976a7..b63e97fdc4a97 100644 --- a/camera/libcameraservice/CameraService.cpp +++ b/camera/libcameraservice/CameraService.cpp @@ -563,7 +563,19 @@ status_t CameraService::Client::setOverlay() status_t ret = NO_ERROR; if (mSurface != 0) { if (mOverlayRef.get() == NULL) { - mOverlayRef = mSurface->createOverlay(w, h, OVERLAY_FORMAT_DEFAULT); + + // FIXME: + // Surfaceflinger may hold onto the previous overlay reference for some + // time after we try to destroy it. retry a few times. In the future, we + // should make the destroy call block, or possibly specify that we can + // wait in the createOverlay call if the previous overlay is in the + // process of being destroyed. + for (int retry = 0; retry < 50; ++retry) { + mOverlayRef = mSurface->createOverlay(w, h, OVERLAY_FORMAT_DEFAULT); + if (mOverlayRef != NULL) break; + LOGD("Overlay create failed - retrying"); + usleep(20000); + } if ( mOverlayRef.get() == NULL ) { LOGE("Overlay Creation Failed!");