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 17182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinskipackage com.android.server.storage; 18182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 19ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport android.annotation.WorkerThread; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.Notification; 21ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport android.app.NotificationChannel; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.NotificationManager; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.PendingIntent; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent; 26197a0c82a1fbf337ec0a85d36b6b89c3d6e8a0acDianne Hackbornimport android.content.pm.PackageManager; 27ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport android.net.TrafficStats; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder; 29f882efadd378e0476b7362e474f3a20dcf1c0d27Dianne Hackbornimport android.os.Environment; 304b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkeyimport android.os.FileObserver; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler; 32a1e79948ecf1057fe91733baac2759ea91cc1894Jeff Sharkeyimport android.os.HandlerThread; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message; 34532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackbornimport android.os.ResultReceiver; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ServiceManager; 36532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackbornimport android.os.ShellCallback; 37532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackbornimport android.os.ShellCommand; 385ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackbornimport android.os.UserHandle; 39be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkeyimport android.os.storage.StorageManager; 40ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport android.os.storage.VolumeInfo; 41ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport android.text.format.DateUtils; 42ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport android.util.ArrayMap; 438a9b22056b13477f59df934928c00c58b5871c95Joe Onoratoimport android.util.Slog; 44ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 45ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport com.android.internal.messages.nano.SystemMessageProto.SystemMessage; 46ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport com.android.internal.notification.SystemNotificationChannels; 47ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport com.android.internal.util.DumpUtils; 48ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport com.android.internal.util.IndentingPrintWriter; 49ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport com.android.server.EventLogTags; 50ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport com.android.server.IoThread; 51ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport com.android.server.SystemService; 52ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport com.android.server.pm.InstructionSets; 53ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport com.android.server.pm.PackageManagerService; 54ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 55ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport dalvik.system.VMRuntime; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 57be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkeyimport java.io.File; 58be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkeyimport java.io.FileDescriptor; 59ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport java.io.IOException; 60be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkeyimport java.io.PrintWriter; 61ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport java.util.Objects; 62ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkeyimport java.util.UUID; 63532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackbornimport java.util.concurrent.atomic.AtomicInteger; 64be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 66ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * Service that monitors and maintains free space on storage volumes. 67ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * <p> 68ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * As the free space on a volume nears the threshold defined by 69ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * {@link StorageManager#getStorageLowBytes(File)}, this service will clear out 70ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * cached data to keep the disk from entering this low state. 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 72182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinskipublic class DeviceStorageMonitorService extends SystemService { 73ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private static final String TAG = "DeviceStorageMonitorService"; 74be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey 75532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn /** 76532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}: 77532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn * Current int sequence number of the update. 78532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn */ 79532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn public static final String EXTRA_SEQUENCE = "seq"; 80532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 81ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private static final int MSG_CHECK = 1; 82529f91fc8e7e884ef19bef8eb3e4e3a1d69336f4Jeff Sharkey 83ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private static final long DEFAULT_LOG_DELTA_BYTES = 64 * TrafficStats.MB_IN_BYTES; 84ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private static final long DEFAULT_CHECK_INTERVAL = DateUtils.MINUTE_IN_MILLIS; 85be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey 86d42fe85bc93e4a27517555f27a8e7a591a135e19Richard Uhler // com.android.internal.R.string.low_internal_storage_view_text_no_boot 87d42fe85bc93e4a27517555f27a8e7a591a135e19Richard Uhler // hard codes 250MB in the message as the storage space required for the 88d42fe85bc93e4a27517555f27a8e7a591a135e19Richard Uhler // boot image. 89ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private static final long BOOT_IMAGE_STORAGE_REQUIREMENT = 250 * TrafficStats.MB_IN_BYTES; 90ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 91ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private NotificationManager mNotifManager; 92ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 93ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey /** Sequence number used for testing */ 94ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private final AtomicInteger mSeq = new AtomicInteger(1); 95ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey /** Forced level used for testing */ 96ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private volatile int mForceLevel = State.LEVEL_UNKNOWN; 97ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 98ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey /** Map from storage volume UUID to internal state */ 99ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private final ArrayMap<UUID, State> mStates = new ArrayMap<>(); 100ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 101ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey /** 102ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * State for a specific storage volume, including the current "level" that 103ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * we've alerted the user and apps about. 104ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey */ 105ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private static class State { 106ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private static final int LEVEL_UNKNOWN = -1; 107ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private static final int LEVEL_NORMAL = 0; 108ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private static final int LEVEL_LOW = 1; 109ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private static final int LEVEL_FULL = 2; 110ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 111ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey /** Last "level" that we alerted about */ 112ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey public int level = LEVEL_NORMAL; 113ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey /** Last {@link File#getUsableSpace()} that we logged about */ 114ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey public long lastUsableBytes = Long.MAX_VALUE; 115ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 116ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey /** 117ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * Test if the given level transition is "entering" a specific level. 118ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * <p> 119ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * As an example, a transition from {@link #LEVEL_NORMAL} to 120ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * {@link #LEVEL_FULL} is considered to "enter" both {@link #LEVEL_LOW} 121ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * and {@link #LEVEL_FULL}. 122ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey */ 123ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private static boolean isEntering(int level, int oldLevel, int newLevel) { 124ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey return newLevel >= level && (oldLevel < level || oldLevel == LEVEL_UNKNOWN); 125ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } 126ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 127ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey /** 128ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * Test if the given level transition is "leaving" a specific level. 129ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * <p> 130ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * As an example, a transition from {@link #LEVEL_FULL} to 131ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * {@link #LEVEL_NORMAL} is considered to "leave" both 132ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * {@link #LEVEL_FULL} and {@link #LEVEL_LOW}. 133ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey */ 134ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private static boolean isLeaving(int level, int oldLevel, int newLevel) { 135ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey return newLevel < level && (oldLevel >= level || oldLevel == LEVEL_UNKNOWN); 136ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } 137ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 138ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private static String levelToString(int level) { 139ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey switch (level) { 140ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey case State.LEVEL_UNKNOWN: return "UNKNOWN"; 141ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey case State.LEVEL_NORMAL: return "NORMAL"; 142ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey case State.LEVEL_LOW: return "LOW"; 143ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey case State.LEVEL_FULL: return "FULL"; 144ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey default: return Integer.toString(level); 145ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } 146ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } 147ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } 148ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 149182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private CacheFileDeletedObserver mCacheFileDeletedObserver; 1503161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This string is used for ServiceManager access to this class. 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 154182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski static final String SERVICE = "devicestoragemonitor"; 1553161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker 156af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitsch private static final String TV_NOTIFICATION_CHANNEL_ID = "devicestoragemonitor.tv"; 157d6bd6b9f649809dfaa2017a4ab54787a584b7748Dmitri Plotnikov 158a1e79948ecf1057fe91733baac2759ea91cc1894Jeff Sharkey private final HandlerThread mHandlerThread; 159a1e79948ecf1057fe91733baac2759ea91cc1894Jeff Sharkey private final Handler mHandler; 1603161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker 161ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private State findOrCreateState(UUID uuid) { 162ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey State state = mStates.get(uuid); 163ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey if (state == null) { 164ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey state = new State(); 165ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mStates.put(uuid, state); 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 167ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey return state; 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1693161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker 170ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey /** 171ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * Core logic that checks the storage state of every mounted private volume. 172ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * Since this can do heavy I/O, callers should invoke indirectly using 173ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey * {@link #MSG_CHECK}. 174ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey */ 175ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey @WorkerThread 176ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private void check() { 177ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final StorageManager storage = getContext().getSystemService(StorageManager.class); 178ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final int seq = mSeq.get(); 179ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 180ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey // Check every mounted private volume to see if they're low on space 181ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey for (VolumeInfo vol : storage.getWritablePrivateVolumes()) { 182ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final File file = vol.getPath(); 183ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final long fullBytes = storage.getStorageFullBytes(file); 184ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final long lowBytes = storage.getStorageLowBytes(file); 185ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 186ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey // Automatically trim cached data when nearing the low threshold; 187ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey // when it's within 150% of the threshold, we try trimming usage 188ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey // back to 200% of the threshold. 189ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey if (file.getUsableSpace() < (lowBytes * 3) / 2) { 190ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final PackageManagerService pms = (PackageManagerService) ServiceManager 191ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .getService("package"); 192ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey try { 193ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey pms.freeStorage(vol.getFsUuid(), lowBytes * 2, 0); 194ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } catch (IOException e) { 195ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey Slog.w(TAG, e); 196532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 197532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 198532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 199ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey // Send relevant broadcasts and show notifications based on any 200ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey // recently noticed state transitions. 201ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final UUID uuid = StorageManager.convert(vol.getFsUuid()); 202ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final State state = findOrCreateState(uuid); 203ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final long totalBytes = file.getTotalSpace(); 204ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final long usableBytes = file.getUsableSpace(); 205ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 206ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey int oldLevel = state.level; 207ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey int newLevel; 208ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey if (mForceLevel != State.LEVEL_UNKNOWN) { 209ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey // When in testing mode, use unknown old level to force sending 210ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey // of any relevant broadcasts. 211ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey oldLevel = State.LEVEL_UNKNOWN; 212ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey newLevel = mForceLevel; 213ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } else if (usableBytes <= fullBytes) { 214ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey newLevel = State.LEVEL_FULL; 215ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } else if (usableBytes <= lowBytes) { 216ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey newLevel = State.LEVEL_LOW; 217ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } else if (StorageManager.UUID_DEFAULT.equals(uuid) && !isBootImageOnDisk() 218ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey && usableBytes < BOOT_IMAGE_STORAGE_REQUIREMENT) { 219ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey newLevel = State.LEVEL_LOW; 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 221ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey newLevel = State.LEVEL_NORMAL; 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 223ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 224ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey // Log whenever we notice drastic storage changes 225ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey if ((Math.abs(state.lastUsableBytes - usableBytes) > DEFAULT_LOG_DELTA_BYTES) 226ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey || oldLevel != newLevel) { 227ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey EventLogTags.writeStorageState(uuid.toString(), oldLevel, newLevel, 228ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey usableBytes, totalBytes); 229ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey state.lastUsableBytes = usableBytes; 230bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby } 231ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 232ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey updateNotifications(vol, oldLevel, newLevel); 233ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey updateBroadcasts(vol, oldLevel, newLevel, seq); 234ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 235ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey state.level = newLevel; 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2373161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker 238ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey // Loop around to check again in future; we don't remove messages since 239ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey // there might be an immediate request pending. 240ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey if (!mHandler.hasMessages(MSG_CHECK)) { 241ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHECK), 242ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey DEFAULT_CHECK_INTERVAL); 243ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2453161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker 246b880d880c6cd989eacc28c365fc9a41d31900da1Jeff Brown public DeviceStorageMonitorService(Context context) { 247b880d880c6cd989eacc28c365fc9a41d31900da1Jeff Brown super(context); 248a1e79948ecf1057fe91733baac2759ea91cc1894Jeff Sharkey 249a1e79948ecf1057fe91733baac2759ea91cc1894Jeff Sharkey mHandlerThread = new HandlerThread(TAG, android.os.Process.THREAD_PRIORITY_BACKGROUND); 250a1e79948ecf1057fe91733baac2759ea91cc1894Jeff Sharkey mHandlerThread.start(); 251a1e79948ecf1057fe91733baac2759ea91cc1894Jeff Sharkey 252a1e79948ecf1057fe91733baac2759ea91cc1894Jeff Sharkey mHandler = new Handler(mHandlerThread.getLooper()) { 253a1e79948ecf1057fe91733baac2759ea91cc1894Jeff Sharkey @Override 254a1e79948ecf1057fe91733baac2759ea91cc1894Jeff Sharkey public void handleMessage(Message msg) { 255a1e79948ecf1057fe91733baac2759ea91cc1894Jeff Sharkey switch (msg.what) { 256a1e79948ecf1057fe91733baac2759ea91cc1894Jeff Sharkey case MSG_CHECK: 257a1e79948ecf1057fe91733baac2759ea91cc1894Jeff Sharkey check(); 258a1e79948ecf1057fe91733baac2759ea91cc1894Jeff Sharkey return; 259a1e79948ecf1057fe91733baac2759ea91cc1894Jeff Sharkey } 260a1e79948ecf1057fe91733baac2759ea91cc1894Jeff Sharkey } 261a1e79948ecf1057fe91733baac2759ea91cc1894Jeff Sharkey }; 262182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 263be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey 264a39871ef5e9bf6703f18af0725484b06f5c78216Brian Carlstrom private static boolean isBootImageOnDisk() { 265eeea67b8c3678d882d3774edc41242c63daa60faFyodor Kupolov for (String instructionSet : InstructionSets.getAllDexCodeInstructionSets()) { 266a39871ef5e9bf6703f18af0725484b06f5c78216Brian Carlstrom if (!VMRuntime.isBootClassPathOnDisk(instructionSet)) { 267a39871ef5e9bf6703f18af0725484b06f5c78216Brian Carlstrom return false; 268a39871ef5e9bf6703f18af0725484b06f5c78216Brian Carlstrom } 269a39871ef5e9bf6703f18af0725484b06f5c78216Brian Carlstrom } 270a39871ef5e9bf6703f18af0725484b06f5c78216Brian Carlstrom return true; 271a39871ef5e9bf6703f18af0725484b06f5c78216Brian Carlstrom } 272a39871ef5e9bf6703f18af0725484b06f5c78216Brian Carlstrom 273182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski @Override 274182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski public void onStart() { 275ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final Context context = getContext(); 276ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mNotifManager = context.getSystemService(NotificationManager.class); 2774b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey 2784b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey mCacheFileDeletedObserver = new CacheFileDeletedObserver(); 2794b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey mCacheFileDeletedObserver.startWatching(); 280182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 281d6bd6b9f649809dfaa2017a4ab54787a584b7748Dmitri Plotnikov // Ensure that the notification channel is set up 282d6bd6b9f649809dfaa2017a4ab54787a584b7748Dmitri Plotnikov PackageManager packageManager = context.getPackageManager(); 283d6bd6b9f649809dfaa2017a4ab54787a584b7748Dmitri Plotnikov boolean isTv = packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK); 284d6bd6b9f649809dfaa2017a4ab54787a584b7748Dmitri Plotnikov 285af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitsch if (isTv) { 286ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mNotifManager.createNotificationChannel(new NotificationChannel( 287af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitsch TV_NOTIFICATION_CHANNEL_ID, 288af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitsch context.getString( 289af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitsch com.android.internal.R.string.device_storage_monitor_notification_channel), 290af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitsch NotificationManager.IMPORTANCE_HIGH)); 291af759c52ce01fe6b5144957e38da956af01a217bGeoffrey Pitsch } 292d6bd6b9f649809dfaa2017a4ab54787a584b7748Dmitri Plotnikov 293182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski publishBinderService(SERVICE, mRemoteService); 294182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski publishLocalService(DeviceStorageMonitorInternal.class, mLocalService); 295ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 296ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey // Kick off pass to examine storage state 297ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mHandler.removeMessages(MSG_CHECK); 298ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mHandler.obtainMessage(MSG_CHECK).sendToTarget(); 299182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 300182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 301182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private final DeviceStorageMonitorInternal mLocalService = new DeviceStorageMonitorInternal() { 302182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski @Override 303182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski public void checkMemory() { 304ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey // Kick off pass to examine storage state 305ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mHandler.removeMessages(MSG_CHECK); 306ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mHandler.obtainMessage(MSG_CHECK).sendToTarget(); 307182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 308182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 309182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski @Override 310182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski public boolean isMemoryLow() { 311ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey return Environment.getDataDirectory().getUsableSpace() < getMemoryLowThreshold(); 312182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 313182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 314182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski @Override 315182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski public long getMemoryLowThreshold() { 316ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey return getContext().getSystemService(StorageManager.class) 317ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .getStorageLowBytes(Environment.getDataDirectory()); 318182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 319182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski }; 320182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 321532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn private final Binder mRemoteService = new Binder() { 322182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski @Override 323182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 324fe9a53bc45fd0124a876dc0a49680aaf86641d3eJeff Sharkey if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return; 325532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn dumpImpl(fd, pw, args); 326532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 327532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 328532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn @Override 329532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn public void onShellCommand(FileDescriptor in, FileDescriptor out, 330532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn FileDescriptor err, String[] args, ShellCallback callback, 331532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn ResultReceiver resultReceiver) { 332532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn (new Shell()).exec(this, in, out, err, args, callback, resultReceiver); 333182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 334182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski }; 335182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 336532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn class Shell extends ShellCommand { 337532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn @Override 338532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn public int onCommand(String cmd) { 339532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn return onShellCommand(this, cmd); 340532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 341532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 342532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn @Override 343532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn public void onHelp() { 344532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn PrintWriter pw = getOutPrintWriter(); 345532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn dumpHelp(pw); 346532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 347532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 348532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 349532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn static final int OPTION_FORCE_UPDATE = 1<<0; 350182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 351532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn int parseOptions(Shell shell) { 352532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn String opt; 353532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn int opts = 0; 354532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn while ((opt = shell.getNextOption()) != null) { 355532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn if ("-f".equals(opt)) { 356532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn opts |= OPTION_FORCE_UPDATE; 357532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 358532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 359532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn return opts; 360532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 361182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 362532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn int onShellCommand(Shell shell, String cmd) { 363532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn if (cmd == null) { 364532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn return shell.handleDefaultCommands(cmd); 365532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 366532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn PrintWriter pw = shell.getOutPrintWriter(); 367532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn switch (cmd) { 368532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn case "force-low": { 369532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn int opts = parseOptions(shell); 370532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn getContext().enforceCallingOrSelfPermission( 371532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn android.Manifest.permission.DEVICE_POWER, null); 372ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mForceLevel = State.LEVEL_LOW; 373532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn int seq = mSeq.incrementAndGet(); 374532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn if ((opts & OPTION_FORCE_UPDATE) != 0) { 375ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mHandler.removeMessages(MSG_CHECK); 376ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mHandler.obtainMessage(MSG_CHECK).sendToTarget(); 377532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println(seq); 378532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 379532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } break; 380532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn case "force-not-low": { 381532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn int opts = parseOptions(shell); 382532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn getContext().enforceCallingOrSelfPermission( 383532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn android.Manifest.permission.DEVICE_POWER, null); 384ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mForceLevel = State.LEVEL_NORMAL; 385532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn int seq = mSeq.incrementAndGet(); 386532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn if ((opts & OPTION_FORCE_UPDATE) != 0) { 387ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mHandler.removeMessages(MSG_CHECK); 388ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mHandler.obtainMessage(MSG_CHECK).sendToTarget(); 389532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println(seq); 390532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 391532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } break; 392532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn case "reset": { 393532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn int opts = parseOptions(shell); 394532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn getContext().enforceCallingOrSelfPermission( 395532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn android.Manifest.permission.DEVICE_POWER, null); 396ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mForceLevel = State.LEVEL_UNKNOWN; 397532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn int seq = mSeq.incrementAndGet(); 398532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn if ((opts & OPTION_FORCE_UPDATE) != 0) { 399ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mHandler.removeMessages(MSG_CHECK); 400ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mHandler.obtainMessage(MSG_CHECK).sendToTarget(); 401532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println(seq); 402532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 403532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } break; 404532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn default: 405532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn return shell.handleDefaultCommands(cmd); 406532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 407532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn return 0; 408532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 409182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 410532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn static void dumpHelp(PrintWriter pw) { 411532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println("Device storage monitor service (devicestoragemonitor) commands:"); 412532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println(" help"); 413532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println(" Print this help text."); 414532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println(" force-low [-f]"); 415532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println(" Force storage to be low, freezing storage state."); 416532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println(" -f: force a storage change broadcast be sent, prints new sequence."); 417532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println(" force-not-low [-f]"); 418532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println(" Force storage to not be low, freezing storage state."); 419532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println(" -f: force a storage change broadcast be sent, prints new sequence."); 420532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println(" reset [-f]"); 421532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println(" Unfreeze storage state, returning to current real values."); 422532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn pw.println(" -f: force a storage change broadcast be sent, prints new sequence."); 423532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 424182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 425ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey void dumpImpl(FileDescriptor fd, PrintWriter _pw, String[] args) { 426ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final IndentingPrintWriter pw = new IndentingPrintWriter(_pw, " "); 427532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn if (args == null || args.length == 0 || "-a".equals(args[0])) { 428ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey pw.println("Known volumes:"); 429ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey pw.increaseIndent(); 430ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey for (int i = 0; i < mStates.size(); i++) { 431ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final UUID uuid = mStates.keyAt(i); 432ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final State state = mStates.valueAt(i); 433ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey if (StorageManager.UUID_DEFAULT.equals(uuid)) { 434ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey pw.println("Default:"); 435ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } else { 436ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey pw.println(uuid + ":"); 437ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } 438ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey pw.increaseIndent(); 439ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey pw.printPair("level", State.levelToString(state.level)); 440ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey pw.printPair("lastUsableBytes", state.lastUsableBytes); 441ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey pw.println(); 442ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey pw.decreaseIndent(); 443532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 444ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey pw.decreaseIndent(); 445ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey pw.println(); 446532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 447ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey pw.printPair("mSeq", mSeq.get()); 448ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey pw.printPair("mForceState", State.levelToString(mForceLevel)); 449ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey pw.println(); 450ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey pw.println(); 451532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn 452532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } else { 453532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn Shell shell = new Shell(); 454532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn shell.exec(mRemoteService, null, fd, null, args, null, new ResultReceiver(null)); 455532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4573161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker 458ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private void updateNotifications(VolumeInfo vol, int oldLevel, int newLevel) { 459182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski final Context context = getContext(); 460ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final UUID uuid = StorageManager.convert(vol.getFsUuid()); 461ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 462ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey if (State.isEntering(State.LEVEL_LOW, oldLevel, newLevel)) { 463ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey Intent lowMemIntent = new Intent(StorageManager.ACTION_MANAGE_STORAGE); 464ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey lowMemIntent.putExtra(StorageManager.EXTRA_UUID, uuid); 465ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey lowMemIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 466ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 467ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final CharSequence title = context.getText( 468ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey com.android.internal.R.string.low_internal_storage_view_title); 469ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 470ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final CharSequence details; 471ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey if (StorageManager.UUID_DEFAULT.equals(uuid)) { 472ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey details = context.getText(isBootImageOnDisk() 473ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey ? com.android.internal.R.string.low_internal_storage_view_text 474ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey : com.android.internal.R.string.low_internal_storage_view_text_no_boot); 475ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } else { 476ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey details = context.getText( 477ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey com.android.internal.R.string.low_internal_storage_view_text); 478ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } 479ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 480ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey PendingIntent intent = PendingIntent.getActivityAsUser(context, 0, lowMemIntent, 0, 481ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey null, UserHandle.CURRENT); 482ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey Notification notification = 483ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey new Notification.Builder(context, SystemNotificationChannels.ALERTS) 484ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .setSmallIcon(com.android.internal.R.drawable.stat_notify_disk_full) 485ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .setTicker(title) 486ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .setColor(context.getColor( 487ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey com.android.internal.R.color.system_notification_accent_color)) 488ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .setContentTitle(title) 489ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .setContentText(details) 490ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .setContentIntent(intent) 491ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .setStyle(new Notification.BigTextStyle() 492ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .bigText(details)) 493ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .setVisibility(Notification.VISIBILITY_PUBLIC) 494ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .setCategory(Notification.CATEGORY_SYSTEM) 495ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .extend(new Notification.TvExtender() 496ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .setChannelId(TV_NOTIFICATION_CHANNEL_ID)) 497ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .build(); 498ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey notification.flags |= Notification.FLAG_NO_CLEAR; 499ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mNotifManager.notifyAsUser(uuid.toString(), SystemMessage.NOTE_LOW_STORAGE, 500ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey notification, UserHandle.ALL); 501ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } else if (State.isLeaving(State.LEVEL_LOW, oldLevel, newLevel)) { 502ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey mNotifManager.cancelAsUser(uuid.toString(), SystemMessage.NOTE_LOW_STORAGE, 503ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey UserHandle.ALL); 504532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 507ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey private void updateBroadcasts(VolumeInfo vol, int oldLevel, int newLevel, int seq) { 508ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, vol.getFsUuid())) { 509ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey // We don't currently send broadcasts for secondary volumes 510ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey return; 511532ea26c7b66180b09524f96da8bca1110f41197Dianne Hackborn } 5123161795b2353171bb0636fb3ea6dab7dec80a4f4Doug Zongker 513ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final Intent lowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_LOW) 514ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 515ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND 516ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) 517ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .putExtra(EXTRA_SEQUENCE, seq); 518ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final Intent notLowIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_OK) 519ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 520ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND 521ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) 522ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .putExtra(EXTRA_SEQUENCE, seq); 523ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 524ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey if (State.isEntering(State.LEVEL_LOW, oldLevel, newLevel)) { 525ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey getContext().sendStickyBroadcastAsUser(lowIntent, UserHandle.ALL); 526ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } else if (State.isLeaving(State.LEVEL_LOW, oldLevel, newLevel)) { 527ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey getContext().removeStickyBroadcastAsUser(lowIntent, UserHandle.ALL); 528ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey getContext().sendBroadcastAsUser(notLowIntent, UserHandle.ALL); 529ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } 530bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby 531ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final Intent fullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_FULL) 532ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) 533ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .putExtra(EXTRA_SEQUENCE, seq); 534ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey final Intent notFullIntent = new Intent(Intent.ACTION_DEVICE_STORAGE_NOT_FULL) 535ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) 536ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey .putExtra(EXTRA_SEQUENCE, seq); 537ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey 538ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey if (State.isEntering(State.LEVEL_FULL, oldLevel, newLevel)) { 539ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey getContext().sendStickyBroadcastAsUser(fullIntent, UserHandle.ALL); 540ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } else if (State.isLeaving(State.LEVEL_FULL, oldLevel, newLevel)) { 541ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey getContext().removeStickyBroadcastAsUser(fullIntent, UserHandle.ALL); 542ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey getContext().sendBroadcastAsUser(notFullIntent, UserHandle.ALL); 543ddff807b762a8a455287abc97aea8f97b98fb104Jeff Sharkey } 544bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby } 545bb3716332321e22537a5015be13e2229fb9b90bcJake Hamby 546182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private static class CacheFileDeletedObserver extends FileObserver { 5474b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey public CacheFileDeletedObserver() { 5484b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey super(Environment.getDownloadCacheDirectory().getAbsolutePath(), FileObserver.DELETE); 5494b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey } 5504b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey 5514b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey @Override 5524b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey public void onEvent(int event, String path) { 5534b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey EventLogTags.writeCacheFileDeleted(path); 5544b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey } 5554b49657c7f78f8cee30804f8b31a004a11fffd7fJeff Sharkey } 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 557