blob: 0ed5189dd0e969a8fbe659315d53668df9b4cb74 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.app.Notification;
20import android.app.NotificationManager;
21import android.app.PendingIntent;
22import android.content.ContentResolver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.pm.IPackageDataObserver;
26import android.content.pm.IPackageManager;
27import android.os.Binder;
Dianne Hackbornf882efa2012-04-11 16:04:12 -070028import android.os.Environment;
Jeff Sharkey4b496572012-04-19 14:17:03 -070029import android.os.FileObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.os.Handler;
31import android.os.Message;
32import android.os.Process;
33import android.os.RemoteException;
34import android.os.ServiceManager;
35import android.os.StatFs;
36import android.os.SystemClock;
37import android.os.SystemProperties;
Doug Zongker43866e02010-01-07 12:09:54 -080038import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.util.EventLog;
Joe Onorato8a9b2202010-02-26 18:56:32 -080040import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041
42/**
Doug Zongker43866e02010-01-07 12:09:54 -080043 * This class implements a service to monitor the amount of disk
44 * storage space on the device. If the free storage on device is less
45 * than a tunable threshold value (a secure settings parameter;
46 * default 10%) a low memory notification is displayed to alert the
47 * user. If the user clicks on the low memory notification the
48 * Application Manager application gets launched to let the user free
49 * storage space.
50 *
51 * Event log events: A low memory event with the free storage on
52 * device in bytes is logged to the event log when the device goes low
53 * on storage space. The amount of free storage on the device is
54 * periodically logged to the event log. The log interval is a secure
55 * settings parameter with a default value of 12 hours. When the free
56 * storage differential goes below a threshold (again a secure
57 * settings parameter with a default value of 2MB), the free memory is
58 * logged to the event log.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059 */
Kenny Rootcf0b38c2011-03-22 14:17:59 -070060public class DeviceStorageMonitorService extends Binder {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061 private static final String TAG = "DeviceStorageMonitorService";
62 private static final boolean DEBUG = false;
Joe Onorato43a17652011-04-06 19:22:23 -070063 private static final boolean localLOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064 private static final int DEVICE_MEMORY_WHAT = 1;
65 private static final int MONITOR_INTERVAL = 1; //in minutes
66 private static final int LOW_MEMORY_NOTIFICATION_ID = 1;
67 private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10;
Dianne Hackborn247fe742011-01-08 17:25:57 -080068 private static final int DEFAULT_THRESHOLD_MAX_BYTES = 500*1024*1024; // 500MB
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069 private static final int DEFAULT_FREE_STORAGE_LOG_INTERVAL_IN_MINUTES = 12*60; //in minutes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070 private static final long DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD = 2 * 1024 * 1024; // 2MB
71 private static final long DEFAULT_CHECK_INTERVAL = MONITOR_INTERVAL*60*1000;
Jake Hambybb371632010-08-23 18:16:48 -070072 private static final int DEFAULT_FULL_THRESHOLD_BYTES = 1024*1024; // 1MB
Doug Zongker3161795b2009-10-07 15:14:03 -070073 private long mFreeMem; // on /data
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 private long mLastReportedFreeMem;
75 private long mLastReportedFreeMemTime;
76 private boolean mLowMemFlag=false;
Jake Hambybb371632010-08-23 18:16:48 -070077 private boolean mMemFullFlag=false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078 private Context mContext;
79 private ContentResolver mContentResolver;
Doug Zongker3161795b2009-10-07 15:14:03 -070080 private long mTotalMemory; // on /data
81 private StatFs mDataFileStats;
82 private StatFs mSystemFileStats;
83 private StatFs mCacheFileStats;
84 private static final String DATA_PATH = "/data";
85 private static final String SYSTEM_PATH = "/system";
86 private static final String CACHE_PATH = "/cache";
87 private long mThreadStartTime = -1;
88 private boolean mClearSucceeded = false;
89 private boolean mClearingCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 private Intent mStorageLowIntent;
91 private Intent mStorageOkIntent;
Jake Hambybb371632010-08-23 18:16:48 -070092 private Intent mStorageFullIntent;
93 private Intent mStorageNotFullIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094 private CachePackageDataObserver mClearCacheObserver;
Jeff Sharkey4b496572012-04-19 14:17:03 -070095 private final CacheFileDeletedObserver mCacheFileDeletedObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 private static final int _TRUE = 1;
97 private static final int _FALSE = 0;
Jake Hambybb371632010-08-23 18:16:48 -070098 private long mMemLowThreshold;
99 private int mMemFullThreshold;
Doug Zongker3161795b2009-10-07 15:14:03 -0700100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 /**
102 * This string is used for ServiceManager access to this class.
103 */
Kenny Rootcf0b38c2011-03-22 14:17:59 -0700104 public static final String SERVICE = "devicestoragemonitor";
Doug Zongker3161795b2009-10-07 15:14:03 -0700105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 /**
Doug Zongker3161795b2009-10-07 15:14:03 -0700107 * Handler that checks the amount of disk space on the device and sends a
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 * notification if the device runs low on disk space
109 */
110 Handler mHandler = new Handler() {
111 @Override
112 public void handleMessage(Message msg) {
Jake Hambybb371632010-08-23 18:16:48 -0700113 //don't handle an invalid message
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 if (msg.what != DEVICE_MEMORY_WHAT) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800115 Slog.e(TAG, "Will not process invalid message");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 return;
117 }
118 checkMemory(msg.arg1 == _TRUE);
119 }
120 };
Doug Zongker3161795b2009-10-07 15:14:03 -0700121
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 class CachePackageDataObserver extends IPackageDataObserver.Stub {
123 public void onRemoveCompleted(String packageName, boolean succeeded) {
124 mClearSucceeded = succeeded;
125 mClearingCache = false;
Joe Onorato8a9b2202010-02-26 18:56:32 -0800126 if(localLOGV) Slog.i(TAG, " Clear succeeded:"+mClearSucceeded
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 +", mClearingCache:"+mClearingCache+" Forcing memory check");
128 postCheckMemoryMsg(false, 0);
Doug Zongker3161795b2009-10-07 15:14:03 -0700129 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 }
Doug Zongker3161795b2009-10-07 15:14:03 -0700131
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 private final void restatDataDir() {
Doug Zongker3161795b2009-10-07 15:14:03 -0700133 try {
134 mDataFileStats.restat(DATA_PATH);
135 mFreeMem = (long) mDataFileStats.getAvailableBlocks() *
136 mDataFileStats.getBlockSize();
137 } catch (IllegalArgumentException e) {
138 // use the old value of mFreeMem
139 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 // Allow freemem to be overridden by debug.freemem for testing
141 String debugFreeMem = SystemProperties.get("debug.freemem");
142 if (!"".equals(debugFreeMem)) {
143 mFreeMem = Long.parseLong(debugFreeMem);
144 }
Doug Zongker43866e02010-01-07 12:09:54 -0800145 // Read the log interval from secure settings
146 long freeMemLogInterval = Settings.Secure.getLong(mContentResolver,
147 Settings.Secure.SYS_FREE_STORAGE_LOG_INTERVAL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 DEFAULT_FREE_STORAGE_LOG_INTERVAL_IN_MINUTES)*60*1000;
149 //log the amount of free memory in event log
150 long currTime = SystemClock.elapsedRealtime();
Doug Zongker3161795b2009-10-07 15:14:03 -0700151 if((mLastReportedFreeMemTime == 0) ||
152 (currTime-mLastReportedFreeMemTime) >= freeMemLogInterval) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 mLastReportedFreeMemTime = currTime;
Doug Zongker3161795b2009-10-07 15:14:03 -0700154 long mFreeSystem = -1, mFreeCache = -1;
155 try {
156 mSystemFileStats.restat(SYSTEM_PATH);
157 mFreeSystem = (long) mSystemFileStats.getAvailableBlocks() *
158 mSystemFileStats.getBlockSize();
159 } catch (IllegalArgumentException e) {
160 // ignore; report -1
161 }
162 try {
163 mCacheFileStats.restat(CACHE_PATH);
164 mFreeCache = (long) mCacheFileStats.getAvailableBlocks() *
165 mCacheFileStats.getBlockSize();
166 } catch (IllegalArgumentException e) {
167 // ignore; report -1
168 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800169 EventLog.writeEvent(EventLogTags.FREE_STORAGE_LEFT,
Doug Zongker3161795b2009-10-07 15:14:03 -0700170 mFreeMem, mFreeSystem, mFreeCache);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 }
Doug Zongker43866e02010-01-07 12:09:54 -0800172 // Read the reporting threshold from secure settings
173 long threshold = Settings.Secure.getLong(mContentResolver,
174 Settings.Secure.DISK_FREE_CHANGE_REPORTING_THRESHOLD,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 DEFAULT_DISK_FREE_CHANGE_REPORTING_THRESHOLD);
176 // If mFree changed significantly log the new value
177 long delta = mFreeMem - mLastReportedFreeMem;
178 if (delta > threshold || delta < -threshold) {
179 mLastReportedFreeMem = mFreeMem;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800180 EventLog.writeEvent(EventLogTags.FREE_STORAGE_CHANGED, mFreeMem);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 }
182 }
Doug Zongker3161795b2009-10-07 15:14:03 -0700183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 private final void clearCache() {
185 if (mClearCacheObserver == null) {
186 // Lazy instantiation
187 mClearCacheObserver = new CachePackageDataObserver();
188 }
189 mClearingCache = true;
190 try {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800191 if (localLOGV) Slog.i(TAG, "Clearing cache");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 IPackageManager.Stub.asInterface(ServiceManager.getService("package")).
Jake Hambybb371632010-08-23 18:16:48 -0700193 freeStorageAndNotify(mMemLowThreshold, mClearCacheObserver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800195 Slog.w(TAG, "Failed to get handle for PackageManger Exception: "+e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 mClearingCache = false;
197 mClearSucceeded = false;
198 }
199 }
Doug Zongker3161795b2009-10-07 15:14:03 -0700200
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 private final void checkMemory(boolean checkCache) {
Doug Zongker3161795b2009-10-07 15:14:03 -0700202 //if the thread that was started to clear cache is still running do nothing till its
203 //finished clearing cache. Ideally this flag could be modified by clearCache
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 // and should be accessed via a lock but even if it does this test will fail now and
205 //hopefully the next time this flag will be set to the correct value.
206 if(mClearingCache) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800207 if(localLOGV) Slog.i(TAG, "Thread already running just skip");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 //make sure the thread is not hung for too long
209 long diffTime = System.currentTimeMillis() - mThreadStartTime;
210 if(diffTime > (10*60*1000)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800211 Slog.w(TAG, "Thread that clears cache file seems to run for ever");
Doug Zongker3161795b2009-10-07 15:14:03 -0700212 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 } else {
214 restatDataDir();
Joe Onorato8a9b2202010-02-26 18:56:32 -0800215 if (localLOGV) Slog.v(TAG, "freeMemory="+mFreeMem);
Doug Zongker3161795b2009-10-07 15:14:03 -0700216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 //post intent to NotificationManager to display icon if necessary
Jake Hambybb371632010-08-23 18:16:48 -0700218 if (mFreeMem < mMemLowThreshold) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 if (!mLowMemFlag) {
220 if (checkCache) {
221 // See if clearing cache helps
222 // Note that clearing cache is asynchronous and so we do a
223 // memory check again once the cache has been cleared.
224 mThreadStartTime = System.currentTimeMillis();
225 mClearSucceeded = false;
226 clearCache();
227 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800228 Slog.i(TAG, "Running low on memory. Sending notification");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 sendNotification();
230 mLowMemFlag = true;
231 }
232 } else {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800233 if (localLOGV) Slog.v(TAG, "Running low on memory " +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 "notification already sent. do nothing");
235 }
236 } else {
237 if (mLowMemFlag) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800238 Slog.i(TAG, "Memory available. Cancelling notification");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 cancelNotification();
240 mLowMemFlag = false;
241 }
242 }
Jake Hambybb371632010-08-23 18:16:48 -0700243 if (mFreeMem < mMemFullThreshold) {
244 if (!mMemFullFlag) {
245 sendFullNotification();
246 mMemFullFlag = true;
247 }
248 } else {
249 if (mMemFullFlag) {
250 cancelFullNotification();
251 mMemFullFlag = false;
252 }
253 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800255 if(localLOGV) Slog.i(TAG, "Posting Message again");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 //keep posting messages to itself periodically
257 postCheckMemoryMsg(true, DEFAULT_CHECK_INTERVAL);
258 }
Doug Zongker3161795b2009-10-07 15:14:03 -0700259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 private void postCheckMemoryMsg(boolean clearCache, long delay) {
261 // Remove queued messages
262 mHandler.removeMessages(DEVICE_MEMORY_WHAT);
263 mHandler.sendMessageDelayed(mHandler.obtainMessage(DEVICE_MEMORY_WHAT,
264 clearCache ?_TRUE : _FALSE, 0),
265 delay);
266 }
Doug Zongker3161795b2009-10-07 15:14:03 -0700267
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 /*
Doug Zongker3161795b2009-10-07 15:14:03 -0700269 * just query settings to retrieve the memory threshold.
Doug Zongker43866e02010-01-07 12:09:54 -0800270 * Preferred this over using a ContentObserver since Settings.Secure caches the value
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271 * any way
272 */
273 private long getMemThreshold() {
Dianne Hackborn247fe742011-01-08 17:25:57 -0800274 long value = Settings.Secure.getInt(
Doug Zongker3161795b2009-10-07 15:14:03 -0700275 mContentResolver,
Doug Zongker43866e02010-01-07 12:09:54 -0800276 Settings.Secure.SYS_STORAGE_THRESHOLD_PERCENTAGE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277 DEFAULT_THRESHOLD_PERCENTAGE);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800278 if(localLOGV) Slog.v(TAG, "Threshold Percentage="+value);
Dianne Hackborn247fe742011-01-08 17:25:57 -0800279 value *= mTotalMemory;
280 long maxValue = Settings.Secure.getInt(
281 mContentResolver,
282 Settings.Secure.SYS_STORAGE_THRESHOLD_MAX_BYTES,
283 DEFAULT_THRESHOLD_MAX_BYTES);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 //evaluate threshold value
Dianne Hackborn247fe742011-01-08 17:25:57 -0800285 return value < maxValue ? value : maxValue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 }
287
Jake Hambybb371632010-08-23 18:16:48 -0700288 /*
289 * just query settings to retrieve the memory full threshold.
290 * Preferred this over using a ContentObserver since Settings.Secure caches the value
291 * any way
292 */
293 private int getMemFullThreshold() {
294 int value = Settings.Secure.getInt(
295 mContentResolver,
296 Settings.Secure.SYS_STORAGE_FULL_THRESHOLD_BYTES,
297 DEFAULT_FULL_THRESHOLD_BYTES);
298 if(localLOGV) Slog.v(TAG, "Full Threshold Bytes="+value);
299 return value;
300 }
301
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 /**
303 * Constructor to run service. initializes the disk space threshold value
304 * and posts an empty message to kickstart the process.
305 */
306 public DeviceStorageMonitorService(Context context) {
307 mLastReportedFreeMemTime = 0;
308 mContext = context;
309 mContentResolver = mContext.getContentResolver();
310 //create StatFs object
Doug Zongker3161795b2009-10-07 15:14:03 -0700311 mDataFileStats = new StatFs(DATA_PATH);
312 mSystemFileStats = new StatFs(SYSTEM_PATH);
313 mCacheFileStats = new StatFs(CACHE_PATH);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 //initialize total storage on device
Doug Zongker3161795b2009-10-07 15:14:03 -0700315 mTotalMemory = ((long)mDataFileStats.getBlockCount() *
316 mDataFileStats.getBlockSize())/100L;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 mStorageLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW);
Jeff Hamilton4b330922010-06-04 15:16:06 -0500318 mStorageLowIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 mStorageOkIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK);
Jeff Hamilton4b330922010-06-04 15:16:06 -0500320 mStorageOkIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Jake Hambybb371632010-08-23 18:16:48 -0700321 mStorageFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_FULL);
322 mStorageFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
323 mStorageNotFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_NOT_FULL);
324 mStorageNotFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
325 // cache storage thresholds
326 mMemLowThreshold = getMemThreshold();
327 mMemFullThreshold = getMemFullThreshold();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 checkMemory(true);
Jeff Sharkey4b496572012-04-19 14:17:03 -0700329
330 mCacheFileDeletedObserver = new CacheFileDeletedObserver();
331 mCacheFileDeletedObserver.startWatching();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 }
Doug Zongker3161795b2009-10-07 15:14:03 -0700333
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334
335 /**
336 * This method sends a notification to NotificationManager to display
337 * an error dialog indicating low disk space and launch the Installer
338 * application
339 */
340 private final void sendNotification() {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800341 if(localLOGV) Slog.i(TAG, "Sending low memory notification");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 //log the event to event log with the amount of free storage(in bytes) left on the device
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800343 EventLog.writeEvent(EventLogTags.LOW_STORAGE, mFreeMem);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 // Pack up the values and broadcast them to everyone
Dianne Hackbornf882efa2012-04-11 16:04:12 -0700345 Intent lowMemIntent = new Intent(Environment.isExternalStorageEmulated()
346 ? Settings.ACTION_INTERNAL_STORAGE_SETTINGS
347 : Intent.ACTION_MANAGE_PACKAGE_STORAGE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 lowMemIntent.putExtra("memory", mFreeMem);
349 lowMemIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Doug Zongker3161795b2009-10-07 15:14:03 -0700350 NotificationManager mNotificationMgr =
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 (NotificationManager)mContext.getSystemService(
352 Context.NOTIFICATION_SERVICE);
353 CharSequence title = mContext.getText(
354 com.android.internal.R.string.low_internal_storage_view_title);
355 CharSequence details = mContext.getText(
356 com.android.internal.R.string.low_internal_storage_view_text);
357 PendingIntent intent = PendingIntent.getActivity(mContext, 0, lowMemIntent, 0);
358 Notification notification = new Notification();
359 notification.icon = com.android.internal.R.drawable.stat_notify_disk_full;
360 notification.tickerText = title;
361 notification.flags |= Notification.FLAG_NO_CLEAR;
362 notification.setLatestEventInfo(mContext, title, details, intent);
363 mNotificationMgr.notify(LOW_MEMORY_NOTIFICATION_ID, notification);
364 mContext.sendStickyBroadcast(mStorageLowIntent);
365 }
366
367 /**
368 * Cancels low storage notification and sends OK intent.
369 */
370 private final void cancelNotification() {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800371 if(localLOGV) Slog.i(TAG, "Canceling low memory notification");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 NotificationManager mNotificationMgr =
373 (NotificationManager)mContext.getSystemService(
374 Context.NOTIFICATION_SERVICE);
375 //cancel notification since memory has been freed
376 mNotificationMgr.cancel(LOW_MEMORY_NOTIFICATION_ID);
377
378 mContext.removeStickyBroadcast(mStorageLowIntent);
379 mContext.sendBroadcast(mStorageOkIntent);
380 }
Doug Zongker3161795b2009-10-07 15:14:03 -0700381
Jake Hambybb371632010-08-23 18:16:48 -0700382 /**
383 * Send a notification when storage is full.
384 */
385 private final void sendFullNotification() {
386 if(localLOGV) Slog.i(TAG, "Sending memory full notification");
387 mContext.sendStickyBroadcast(mStorageFullIntent);
388 }
389
390 /**
391 * Cancels memory full notification and sends "not full" intent.
392 */
393 private final void cancelFullNotification() {
394 if(localLOGV) Slog.i(TAG, "Canceling memory full notification");
395 mContext.removeStickyBroadcast(mStorageFullIntent);
396 mContext.sendBroadcast(mStorageNotFullIntent);
397 }
398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 public void updateMemory() {
400 int callingUid = getCallingUid();
401 if(callingUid != Process.SYSTEM_UID) {
402 return;
403 }
404 // force an early check
405 postCheckMemoryMsg(true, 0);
406 }
Kenny Root62e1b4e2011-03-14 17:13:39 -0700407
408 /**
409 * Callable from other things in the system service to obtain the low memory
410 * threshold.
411 *
412 * @return low memory threshold in bytes
413 */
414 public long getMemoryLowThreshold() {
415 return mMemLowThreshold;
416 }
417
418 /**
419 * Callable from other things in the system process to check whether memory
420 * is low.
421 *
422 * @return true is memory is low
423 */
424 public boolean isMemoryLow() {
425 return mLowMemFlag;
426 }
Jeff Sharkey4b496572012-04-19 14:17:03 -0700427
428 public static class CacheFileDeletedObserver extends FileObserver {
429 public CacheFileDeletedObserver() {
430 super(Environment.getDownloadCacheDirectory().getAbsolutePath(), FileObserver.DELETE);
431 }
432
433 @Override
434 public void onEvent(int event, String path) {
435 EventLogTags.writeCacheFileDeleted(path);
436 }
437 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438}