1104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne/* 2104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * Copyright (C) 2011 The Android Open Source Project 3104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * 4104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * Licensed under the Apache License, Version 2.0 (the "License"); 5104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * you may not use this file except in compliance with the License. 6104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * You may obtain a copy of the License at 7104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * 8104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * http://www.apache.org/licenses/LICENSE-2.0 9104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * 10104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * Unless required by applicable law or agreed to in writing, software 11104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * distributed under the License is distributed on an "AS IS" BASIS, 12104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * See the License for the specific language governing permissions and 14104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne * limitations under the License. 15104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne */ 16104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 17104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunnepackage com.android.settings.deviceinfo; 18104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 19da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkeyimport android.app.ActivityManager; 20104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.content.ComponentName; 21104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.content.Context; 22104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.content.Intent; 23104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.content.ServiceConnection; 24104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.content.pm.ApplicationInfo; 25104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.content.pm.IPackageStatsObserver; 26104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.content.pm.PackageManager; 27104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.content.pm.PackageStats; 28da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkeyimport android.content.pm.UserInfo; 29104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.os.Environment; 30fc76a78c458ac90d7e050ffc233cf9e32a2d9c0bJeff Sharkeyimport android.os.Environment.UserEnvironment; 31104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.os.Handler; 32104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.os.HandlerThread; 33104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.os.IBinder; 34104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.os.Looper; 35104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.os.Message; 3690c8b20ccfd8f2e877bfac7cf3e883631af7a3e3Jeff Sharkeyimport android.os.UserHandle; 37da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkeyimport android.os.UserManager; 38104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.os.storage.StorageVolume; 39104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport android.util.Log; 40da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkeyimport android.util.SparseLongArray; 41104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 42104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport com.android.internal.app.IMediaContainerService; 4390c8b20ccfd8f2e877bfac7cf3e883631af7a3e3Jeff Sharkeyimport com.google.android.collect.Maps; 44da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkeyimport com.google.common.collect.Sets; 45104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 46104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport java.io.File; 47104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport java.lang.ref.WeakReference; 48104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport java.util.ArrayList; 49104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport java.util.Collections; 5090c8b20ccfd8f2e877bfac7cf3e883631af7a3e3Jeff Sharkeyimport java.util.HashMap; 51104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunneimport java.util.List; 52da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkeyimport java.util.Set; 53da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey 54da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkeyimport javax.annotation.concurrent.GuardedBy; 55104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 56104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne/** 57da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * Utility for measuring the disk usage of internal storage or a physical 58da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * {@link StorageVolume}. Connects with a remote {@link IMediaContainerService} 59da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * and delivers results to {@link MeasurementReceiver}. 60104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne */ 61104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunnepublic class StorageMeasurement { 62104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne private static final String TAG = "StorageMeasurement"; 63104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 64104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne private static final boolean LOCAL_LOGV = true; 65104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne static final boolean LOGV = LOCAL_LOGV && Log.isLoggable(TAG, Log.VERBOSE); 66104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 67da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer"; 68104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 69da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey public static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName( 70da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey DEFAULT_CONTAINER_PACKAGE, "com.android.defcontainer.DefaultContainerService"); 71104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 72da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey /** Media types to measure on external storage. */ 73da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private static final Set<String> sMeasureMediaTypes = Sets.newHashSet( 74da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey Environment.DIRECTORY_DCIM, Environment.DIRECTORY_MOVIES, 75da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey Environment.DIRECTORY_PICTURES, Environment.DIRECTORY_MUSIC, 76da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey Environment.DIRECTORY_ALARMS, Environment.DIRECTORY_NOTIFICATIONS, 77da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey Environment.DIRECTORY_RINGTONES, Environment.DIRECTORY_PODCASTS, 78da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey Environment.DIRECTORY_DOWNLOADS, Environment.DIRECTORY_ANDROID); 79104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 80da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey @GuardedBy("sInstances") 81da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private static HashMap<StorageVolume, StorageMeasurement> sInstances = Maps.newHashMap(); 82104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 83da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey /** 84da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * Obtain shared instance of {@link StorageMeasurement} for given physical 85da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * {@link StorageVolume}, or internal storage if {@code null}. 86da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey */ 87da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey public static StorageMeasurement getInstance(Context context, StorageVolume volume) { 88da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey synchronized (sInstances) { 89da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey StorageMeasurement value = sInstances.get(volume); 90da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey if (value == null) { 91da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey value = new StorageMeasurement(context.getApplicationContext(), volume); 92da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey sInstances.put(volume, value); 93da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey } 94da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey return value; 95da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey } 96da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey } 97104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 98da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey public static class MeasurementDetails { 99ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey public long totalSize; 100ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey public long availSize; 101ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey 102da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey /** 103da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * Total apps disk usage. 104da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * <p> 105da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * When measuring internal storage, this value includes the code size of 106da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * all apps (regardless of install status for current user), and 107da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * internal disk used by the current user's apps. When the device 108da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * emulates external storage, this value also includes emulated storage 109da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * used by the current user's apps. 110da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * <p> 111da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * When measuring a physical {@link StorageVolume}, this value includes 112da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * usage by all apps on that volume. 113da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey */ 114da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey public long appsSize; 115104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 116da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey /** 117ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey * Total cache disk usage by apps. 118ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey */ 119ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey public long cacheSize; 120ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey 121ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey /** 122da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * Total media disk usage, categorized by types such as 123da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * {@link Environment#DIRECTORY_MUSIC}. 124da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * <p> 125da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * When measuring internal storage, this reflects media on emulated 126da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * storage for the current user. 127da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * <p> 128da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * When measuring a physical {@link StorageVolume}, this reflects media 129da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * on that volume. 130da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey */ 131da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey public HashMap<String, Long> mediaSize = Maps.newHashMap(); 132104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 133da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey /** 134da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * Misc external disk usage for the current user, unaccounted in 135da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * {@link #mediaSize}. 136da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey */ 137da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey public long miscSize; 138104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 139da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey /** 140da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * Total disk usage for users, which is only meaningful for emulated 141da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey * internal storage. Key is {@link UserHandle}. 142da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey */ 143da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey public SparseLongArray usersSize = new SparseLongArray(); 144da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey } 145104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 146da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey public interface MeasurementReceiver { 147da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey public void updateApproximate(StorageMeasurement meas, long totalSize, long availSize); 148da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey public void updateDetails(StorageMeasurement meas, MeasurementDetails details); 149da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey } 150104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 151104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne private volatile WeakReference<MeasurementReceiver> mReceiver; 152104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 153da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey /** Physical volume being measured, or {@code null} for internal. */ 154da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private final StorageVolume mVolume; 155da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey 15690c8b20ccfd8f2e877bfac7cf3e883631af7a3e3Jeff Sharkey private final boolean mIsInternal; 157da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private final boolean mIsPrimary; 15890c8b20ccfd8f2e877bfac7cf3e883631af7a3e3Jeff Sharkey 159da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private final MeasurementHandler mHandler; 160104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 161da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private long mTotalSize; 162da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private long mAvailSize; 163104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 164da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey List<FileInfo> mFileInfoForMisc; 165104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 166da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private StorageMeasurement(Context context, StorageVolume volume) { 167da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey mVolume = volume; 16896c2f8c50865e823e710be4d92f1589f978f03c2Jeff Sharkey mIsInternal = volume == null; 16996c2f8c50865e823e710be4d92f1589f978f03c2Jeff Sharkey mIsPrimary = volume != null ? volume.isPrimary() : false; 170104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 171104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne // Start the thread that will measure the disk usage. 172104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne final HandlerThread handlerThread = new HandlerThread("MemoryMeasurement"); 173104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne handlerThread.start(); 174104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mHandler = new MeasurementHandler(context, handlerThread.getLooper()); 175104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 176104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 177104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne public void setReceiver(MeasurementReceiver receiver) { 178104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne if (mReceiver == null || mReceiver.get() == null) { 179104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mReceiver = new WeakReference<MeasurementReceiver>(receiver); 180104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 181104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 182104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 183104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne public void measure() { 184104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne if (!mHandler.hasMessages(MeasurementHandler.MSG_MEASURE)) { 185104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mHandler.sendEmptyMessage(MeasurementHandler.MSG_MEASURE); 186104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 187104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 188104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 189104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne public void cleanUp() { 190104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mReceiver = null; 191104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mHandler.removeMessages(MeasurementHandler.MSG_MEASURE); 192104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mHandler.sendEmptyMessage(MeasurementHandler.MSG_DISCONNECT); 193104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 194104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 195104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne public void invalidate() { 196104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mHandler.sendEmptyMessage(MeasurementHandler.MSG_INVALIDATE); 197104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 198104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 199104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne private void sendInternalApproximateUpdate() { 200104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne MeasurementReceiver receiver = (mReceiver != null) ? mReceiver.get() : null; 201104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne if (receiver == null) { 202104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne return; 203104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 204da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey receiver.updateApproximate(this, mTotalSize, mAvailSize); 205104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 206104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 207da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private void sendExactUpdate(MeasurementDetails details) { 208104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne MeasurementReceiver receiver = (mReceiver != null) ? mReceiver.get() : null; 209104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne if (receiver == null) { 210104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne if (LOGV) { 211104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne Log.i(TAG, "measurements dropped because receiver is null! wasted effort"); 212104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 213104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne return; 214104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 215da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey receiver.updateDetails(this, details); 216da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey } 217104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 218da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private static class StatsObserver extends IPackageStatsObserver.Stub { 219da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private final boolean mIsInternal; 220da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private final MeasurementDetails mDetails; 221da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private final int mCurrentUser; 222da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private final Message mFinished; 223da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey 224da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private int mRemaining; 225da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey 226da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey public StatsObserver(boolean isInternal, MeasurementDetails details, int currentUser, 227da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey Message finished, int remaining) { 228da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey mIsInternal = isInternal; 229da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey mDetails = details; 230da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey mCurrentUser = currentUser; 231da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey mFinished = finished; 232da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey mRemaining = remaining; 233da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey } 234104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 235da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey @Override 236da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey public void onGetStatsCompleted(PackageStats stats, boolean succeeded) { 237da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey synchronized (mDetails) { 238da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey if (succeeded) { 239da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey addStatsLocked(stats); 240da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey } 241da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey if (--mRemaining == 0) { 242da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey mFinished.sendToTarget(); 243da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey } 244da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey } 245da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey } 246da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey 247da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private void addStatsLocked(PackageStats stats) { 248da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey if (mIsInternal) { 249ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey long codeSize = stats.codeSize; 250ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey long dataSize = stats.dataSize; 251ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey long cacheSize = stats.cacheSize; 252da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey if (Environment.isExternalStorageEmulated()) { 253ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey // Include emulated storage when measuring internal. OBB is 254ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey // shared on emulated storage, so treat as code. 255ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey codeSize += stats.externalCodeSize + stats.externalObbSize; 256ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey dataSize += stats.externalDataSize + stats.externalMediaSize; 257ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey cacheSize += stats.externalCacheSize; 258da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey } 259da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey 260ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey // Count code and data for current user 261da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey if (stats.userHandle == mCurrentUser) { 262da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey mDetails.appsSize += codeSize; 263da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey mDetails.appsSize += dataSize; 264da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey } 265da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey 266ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey // User summary only includes data (code is only counted once 267ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey // for the current user) 268da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey addValue(mDetails.usersSize, stats.userHandle, dataSize); 269da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey 270ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey // Include cache for all users 271ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey mDetails.cacheSize += cacheSize; 272ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey 273da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey } else { 274da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey // Physical storage; only count external sizes 275ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey mDetails.appsSize += stats.externalCodeSize + stats.externalDataSize 276ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey + stats.externalMediaSize + stats.externalObbSize; 277ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey mDetails.cacheSize += stats.externalCacheSize; 278da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey } 279da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey } 280104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 281104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 282104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne private class MeasurementHandler extends Handler { 283104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne public static final int MSG_MEASURE = 1; 284104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne public static final int MSG_CONNECTED = 2; 285104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne public static final int MSG_DISCONNECT = 3; 286104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne public static final int MSG_COMPLETED = 4; 287104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne public static final int MSG_INVALIDATE = 5; 288104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 289104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne private Object mLock = new Object(); 290104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 291104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne private IMediaContainerService mDefaultContainer; 292104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 293104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne private volatile boolean mBound = false; 294104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 295da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private MeasurementDetails mCached; 296104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 297104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne private final WeakReference<Context> mContext; 298104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 299da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private final ServiceConnection mDefContainerConn = new ServiceConnection() { 300da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey @Override 301104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne public void onServiceConnected(ComponentName name, IBinder service) { 302da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final IMediaContainerService imcs = IMediaContainerService.Stub.asInterface( 303da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey service); 304104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mDefaultContainer = imcs; 305104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mBound = true; 306104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne sendMessage(obtainMessage(MSG_CONNECTED, imcs)); 307104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 308104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 309da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey @Override 310104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne public void onServiceDisconnected(ComponentName name) { 311104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mBound = false; 312104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne removeMessages(MSG_CONNECTED); 313104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 314104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne }; 315104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 316104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne public MeasurementHandler(Context context, Looper looper) { 317104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne super(looper); 318104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mContext = new WeakReference<Context>(context); 319104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 320104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 321104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne @Override 322104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne public void handleMessage(Message msg) { 323104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne switch (msg.what) { 324104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne case MSG_MEASURE: { 325da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey if (mCached != null) { 326da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey sendExactUpdate(mCached); 327104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne break; 328104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 329104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 330104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne final Context context = (mContext != null) ? mContext.get() : null; 331104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne if (context == null) { 332104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne return; 333104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 334104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 335104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne synchronized (mLock) { 336104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne if (mBound) { 337104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne removeMessages(MSG_DISCONNECT); 338104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne sendMessage(obtainMessage(MSG_CONNECTED, mDefaultContainer)); 339104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } else { 340104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); 341da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey context.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE, 342da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey UserHandle.USER_OWNER); 343104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 344104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 345104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne break; 346104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 347104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne case MSG_CONNECTED: { 348104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne IMediaContainerService imcs = (IMediaContainerService) msg.obj; 34944dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey measureApproximateStorage(imcs); 350104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne measureExactStorage(imcs); 351104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne break; 352104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 353104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne case MSG_DISCONNECT: { 354104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne synchronized (mLock) { 355104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne if (mBound) { 356104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne final Context context = (mContext != null) ? mContext.get() : null; 357104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne if (context == null) { 358104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne return; 359104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 360104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 361104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mBound = false; 362104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne context.unbindService(mDefContainerConn); 363104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 364104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 365104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne break; 366104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 367104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne case MSG_COMPLETED: { 368da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey mCached = (MeasurementDetails) msg.obj; 369da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey sendExactUpdate(mCached); 370104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne break; 371104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 372104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne case MSG_INVALIDATE: { 373da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey mCached = null; 374104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne break; 375104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 376104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 377104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 378104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 37944dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey private void measureApproximateStorage(IMediaContainerService imcs) { 380da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final String path = mVolume != null ? mVolume.getPath() 38144dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey : Environment.getDataDirectory().getPath(); 38244dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey try { 38344dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey final long[] stats = imcs.getFileSystemStats(path); 38444dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey mTotalSize = stats[0]; 38544dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey mAvailSize = stats[1]; 386fc76a78c458ac90d7e050ffc233cf9e32a2d9c0bJeff Sharkey } catch (Exception e) { 38744dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey Log.w(TAG, "Problem in container service", e); 38844dda2d7f52007d2ef33b9e9b9b9b1ec84c5582eJeff Sharkey } 389104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 390104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne sendInternalApproximateUpdate(); 391104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 392104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 393104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne private void measureExactStorage(IMediaContainerService imcs) { 394da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final Context context = mContext != null ? mContext.get() : null; 395104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne if (context == null) { 396104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne return; 397104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 398104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 399da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final MeasurementDetails details = new MeasurementDetails(); 400da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final Message finished = obtainMessage(MSG_COMPLETED, details); 401da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey 402ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey details.totalSize = mTotalSize; 403ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey details.availSize = mAvailSize; 404ec6e66268829e09df3f2b9d68500e672d35a8008Jeff Sharkey 405da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final UserManager userManager = (UserManager) context.getSystemService( 406da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey Context.USER_SERVICE); 407da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final List<UserInfo> users = userManager.getUsers(); 408da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey 409da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final int currentUser = ActivityManager.getCurrentUser(); 410da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final UserEnvironment currentEnv = new UserEnvironment(currentUser); 411da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey 412da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey // Measure media types for emulated storage, or for primary physical 413da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey // external volume 414da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final boolean measureMedia = (mIsInternal && Environment.isExternalStorageEmulated()) 415da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey || mIsPrimary; 416da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey if (measureMedia) { 417da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey for (String type : sMeasureMediaTypes) { 418da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final File path = currentEnv.getExternalStoragePublicDirectory(type); 419da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final long size = getDirectorySize(imcs, path); 420da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey details.mediaSize.put(type, size); 421104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 422104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 423104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 424da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey // Measure misc files not counted under media 425da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey if (mIsInternal || mIsPrimary) { 426da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final File path = mIsInternal ? currentEnv.getExternalStorageDirectory() 427da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey : mVolume.getPathFile(); 428da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey details.miscSize = measureMisc(imcs, path); 429104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 430104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 431da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey // Measure total emulated storage of all users; internal apps data 432da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey // will be spliced in later 433da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey for (UserInfo user : users) { 434da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final UserEnvironment userEnv = new UserEnvironment(user.id); 435da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final long size = getDirectorySize(imcs, userEnv.getExternalStorageDirectory()); 436da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey addValue(details.usersSize, user.id, size); 437104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 438104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 439da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey // Measure all apps for all users 440da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final PackageManager pm = context.getPackageManager(); 441da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey if (mIsInternal || mIsPrimary) { 442da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final List<ApplicationInfo> apps = pm.getInstalledApplications( 443da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey PackageManager.GET_UNINSTALLED_PACKAGES 444da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey | PackageManager.GET_DISABLED_COMPONENTS); 445104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 446da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final int count = users.size() * apps.size(); 447da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final StatsObserver observer = new StatsObserver( 448da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey mIsInternal, details, currentUser, finished, count); 449104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 450da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey for (UserInfo user : users) { 451da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey for (ApplicationInfo app : apps) { 452da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey pm.getPackageSizeInfo(app.packageName, user.id, observer); 453104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 454104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 455104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 456104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } else { 457da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey finished.sendToTarget(); 458104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 459104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 460104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 461104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 462da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private static long getDirectorySize(IMediaContainerService imcs, File path) { 463104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne try { 464da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final long size = imcs.calculateDirectorySize(path.toString()); 465da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey Log.d(TAG, "getDirectorySize(" + path + ") returned " + size); 466da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey return size; 467104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } catch (Exception e) { 468da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey Log.w(TAG, "Could not read memory from default container service for " + path, e); 469104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne return 0; 470104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 471104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 472104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 473da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private long measureMisc(IMediaContainerService imcs, File dir) { 474104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mFileInfoForMisc = new ArrayList<FileInfo>(); 475da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey 476da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final File[] files = dir.listFiles(); 477da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey if (files == null) return 0; 478da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey 479da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey // Get sizes of all top level nodes except the ones already computed 480104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne long counter = 0; 481da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey long miscSize = 0; 482da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey 483da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey for (File file : files) { 484da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final String path = file.getAbsolutePath(); 485da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final String name = file.getName(); 486da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey if (sMeasureMediaTypes.contains(name)) { 487104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne continue; 488104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 489da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey 490da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey if (file.isFile()) { 491da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final long fileSize = file.length(); 492104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mFileInfoForMisc.add(new FileInfo(path, fileSize, counter++)); 493da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey miscSize += fileSize; 494da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey } else if (file.isDirectory()) { 495da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey final long dirSize = getDirectorySize(imcs, file); 496104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mFileInfoForMisc.add(new FileInfo(path, dirSize, counter++)); 497da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey miscSize += dirSize; 498104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } else { 499104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne // Non directory, non file: not listed 500104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 501104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 502da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey 503104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne // sort the list of FileInfo objects collected above in descending order of their sizes 504104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne Collections.sort(mFileInfoForMisc); 505da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey 506da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey return miscSize; 507104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 508104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 509104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne static class FileInfo implements Comparable<FileInfo> { 510104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne final String mFileName; 511104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne final long mSize; 512104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne final long mId; 513104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 514104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne FileInfo(String fileName, long size, long id) { 515104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mFileName = fileName; 516104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mSize = size; 517104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne mId = id; 518104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 519104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 520104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne @Override 521104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne public int compareTo(FileInfo that) { 522104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne if (this == that || mSize == that.mSize) return 0; 523104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne else return (mSize < that.mSize) ? 1 : -1; // for descending sort 524104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 525104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne 526104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne @Override 527104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne public String toString() { 528104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne return mFileName + " : " + mSize + ", id:" + mId; 529104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 530104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne } 5314f734d9d590d0f75a60d744d97218eb54faa4330Gilles Debunne 532da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey private static void addValue(SparseLongArray array, int key, long value) { 533da13ec0cb454f1aadada2acf12291cfaf0a7b176Jeff Sharkey array.put(key, array.get(key) + value); 5344f734d9d590d0f75a60d744d97218eb54faa4330Gilles Debunne } 535104ea2873dff5fa3a5f6bd4cfdb893bac3527fdfGilles Debunne} 536