From d325f5d53cfad674b5284e23702410629de75d0a Mon Sep 17 00:00:00 2001 From: Tony Mantler Date: Thu, 23 Apr 2015 15:19:40 -0700 Subject: [PATCH] Move StorageMeasurement to SettingsLib Change-Id: I00335fe896ef1bae11c382592eea2a354269818a --- .../deviceinfo/PrivateVolumeSettings.java | 5 +- .../deviceinfo/StorageMeasurement.java | 441 ------------------ 2 files changed, 3 insertions(+), 443 deletions(-) delete mode 100644 src/com/android/settings/deviceinfo/StorageMeasurement.java diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java index 00fb0941835..492051dc711 100644 --- a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java +++ b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java @@ -57,9 +57,10 @@ import com.android.settings.Settings.StorageUseActivity; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.Utils; import com.android.settings.applications.ManageApplications; -import com.android.settings.deviceinfo.StorageMeasurement.MeasurementDetails; -import com.android.settings.deviceinfo.StorageMeasurement.MeasurementReceiver; import com.android.settings.deviceinfo.StorageSettings.MountTask; +import com.android.settingslib.deviceinfo.StorageMeasurement; +import com.android.settingslib.deviceinfo.StorageMeasurement.MeasurementDetails; +import com.android.settingslib.deviceinfo.StorageMeasurement.MeasurementReceiver; import com.google.android.collect.Lists; import java.io.File; diff --git a/src/com/android/settings/deviceinfo/StorageMeasurement.java b/src/com/android/settings/deviceinfo/StorageMeasurement.java deleted file mode 100644 index b6c35e30ee1..00000000000 --- a/src/com/android/settings/deviceinfo/StorageMeasurement.java +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.deviceinfo; - -import android.app.ActivityManager; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageStatsObserver; -import android.content.pm.PackageManager; -import android.content.pm.PackageStats; -import android.content.pm.UserInfo; -import android.os.Environment; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.UserHandle; -import android.os.UserManager; -import android.os.storage.StorageVolume; -import android.os.storage.VolumeInfo; -import android.util.Log; -import android.util.SparseLongArray; - -import com.android.internal.app.IMediaContainerService; -import com.android.internal.util.ArrayUtils; -import com.google.android.collect.Sets; - -import java.io.File; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -/** - * Utility for measuring the disk usage of internal storage or a physical - * {@link StorageVolume}. Connects with a remote {@link IMediaContainerService} - * and delivers results to {@link MeasurementReceiver}. - */ -public class StorageMeasurement { - private static final String TAG = "StorageMeasurement"; - - private static final boolean LOCAL_LOGV = true; - static final boolean LOGV = LOCAL_LOGV && Log.isLoggable(TAG, Log.VERBOSE); - - private static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer"; - - public static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName( - DEFAULT_CONTAINER_PACKAGE, "com.android.defcontainer.DefaultContainerService"); - - /** Media types to measure on external storage. */ - private static final Set sMeasureMediaTypes = Sets.newHashSet( - Environment.DIRECTORY_DCIM, Environment.DIRECTORY_MOVIES, - Environment.DIRECTORY_PICTURES, Environment.DIRECTORY_MUSIC, - Environment.DIRECTORY_ALARMS, Environment.DIRECTORY_NOTIFICATIONS, - Environment.DIRECTORY_RINGTONES, Environment.DIRECTORY_PODCASTS, - Environment.DIRECTORY_DOWNLOADS, Environment.DIRECTORY_ANDROID); - - public static class MeasurementDetails { - /** - * Total apps disk usage. - *

- * When measuring internal storage, this value includes the code size of - * all apps (regardless of install status for current user), and - * internal disk used by the current user's apps. When the device - * emulates external storage, this value also includes emulated storage - * used by the current user's apps. - *

- * When measuring a physical {@link StorageVolume}, this value includes - * usage by all apps on that volume. - */ - public long appsSize; - - /** - * Total cache disk usage by apps. - */ - public long cacheSize; - - /** - * Total media disk usage, categorized by types such as - * {@link Environment#DIRECTORY_MUSIC}. - *

- * When measuring internal storage, this reflects media on emulated - * storage for the current user. - *

- * When measuring a physical {@link StorageVolume}, this reflects media - * on that volume. - */ - public HashMap mediaSize = new HashMap<>(); - - /** - * Misc external disk usage for the current user, unaccounted in - * {@link #mediaSize}. - */ - public long miscSize; - - /** - * Total disk usage for users, which is only meaningful for emulated - * internal storage. Key is {@link UserHandle}. - */ - public SparseLongArray usersSize = new SparseLongArray(); - } - - public interface MeasurementReceiver { - public void onDetailsChanged(MeasurementDetails details); - } - - private WeakReference mReceiver; - - private final Context mContext; - - private final VolumeInfo mVolume; - private final VolumeInfo mSharedVolume; - - private final MainHandler mMainHandler; - private final MeasurementHandler mMeasurementHandler; - - public StorageMeasurement(Context context, VolumeInfo volume, VolumeInfo sharedVolume) { - mContext = context.getApplicationContext(); - - mVolume = volume; - mSharedVolume = sharedVolume; - - // Start the thread that will measure the disk usage. - final HandlerThread handlerThread = new HandlerThread("MemoryMeasurement"); - handlerThread.start(); - - mMainHandler = new MainHandler(); - mMeasurementHandler = new MeasurementHandler(handlerThread.getLooper()); - } - - public void setReceiver(MeasurementReceiver receiver) { - if (mReceiver == null || mReceiver.get() == null) { - mReceiver = new WeakReference(receiver); - } - } - - public void forceMeasure() { - invalidate(); - measure(); - } - - public void measure() { - if (!mMeasurementHandler.hasMessages(MeasurementHandler.MSG_MEASURE)) { - mMeasurementHandler.sendEmptyMessage(MeasurementHandler.MSG_MEASURE); - } - } - - public void onDestroy() { - mReceiver = null; - mMeasurementHandler.removeMessages(MeasurementHandler.MSG_MEASURE); - mMeasurementHandler.sendEmptyMessage(MeasurementHandler.MSG_DISCONNECT); - } - - private void invalidate() { - mMeasurementHandler.sendEmptyMessage(MeasurementHandler.MSG_INVALIDATE); - } - - private static class StatsObserver extends IPackageStatsObserver.Stub { - private final boolean mIsPrivate; - private final MeasurementDetails mDetails; - private final int mCurrentUser; - private final Message mFinished; - - private int mRemaining; - - public StatsObserver(boolean isPrivate, MeasurementDetails details, int currentUser, - Message finished, int remaining) { - mIsPrivate = isPrivate; - mDetails = details; - mCurrentUser = currentUser; - mFinished = finished; - mRemaining = remaining; - } - - @Override - public void onGetStatsCompleted(PackageStats stats, boolean succeeded) { - synchronized (mDetails) { - if (succeeded) { - addStatsLocked(stats); - } - if (--mRemaining == 0) { - mFinished.sendToTarget(); - } - } - } - - private void addStatsLocked(PackageStats stats) { - if (mIsPrivate) { - long codeSize = stats.codeSize; - long dataSize = stats.dataSize; - long cacheSize = stats.cacheSize; - if (Environment.isExternalStorageEmulated()) { - // Include emulated storage when measuring internal. OBB is - // shared on emulated storage, so treat as code. - codeSize += stats.externalCodeSize + stats.externalObbSize; - dataSize += stats.externalDataSize + stats.externalMediaSize; - cacheSize += stats.externalCacheSize; - } - - // Count code and data for current user - if (stats.userHandle == mCurrentUser) { - mDetails.appsSize += codeSize; - mDetails.appsSize += dataSize; - } - - // User summary only includes data (code is only counted once - // for the current user) - addValue(mDetails.usersSize, stats.userHandle, dataSize); - - // Include cache for all users - mDetails.cacheSize += cacheSize; - - } else { - // Physical storage; only count external sizes - mDetails.appsSize += stats.externalCodeSize + stats.externalDataSize - + stats.externalMediaSize + stats.externalObbSize; - mDetails.cacheSize += stats.externalCacheSize; - } - } - } - - private class MainHandler extends Handler { - @Override - public void handleMessage(Message msg) { - final MeasurementDetails details = (MeasurementDetails) msg.obj; - final MeasurementReceiver receiver = (mReceiver != null) ? mReceiver.get() : null; - if (receiver != null) { - receiver.onDetailsChanged(details); - } - } - } - - private class MeasurementHandler extends Handler { - public static final int MSG_MEASURE = 1; - public static final int MSG_CONNECTED = 2; - public static final int MSG_DISCONNECT = 3; - public static final int MSG_COMPLETED = 4; - public static final int MSG_INVALIDATE = 5; - - private Object mLock = new Object(); - - private IMediaContainerService mDefaultContainer; - - private volatile boolean mBound = false; - - private MeasurementDetails mCached; - - private final ServiceConnection mDefContainerConn = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - final IMediaContainerService imcs = IMediaContainerService.Stub.asInterface( - service); - mDefaultContainer = imcs; - mBound = true; - sendMessage(obtainMessage(MSG_CONNECTED, imcs)); - } - - @Override - public void onServiceDisconnected(ComponentName name) { - mBound = false; - removeMessages(MSG_CONNECTED); - } - }; - - public MeasurementHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_MEASURE: { - if (mCached != null) { - mMainHandler.obtainMessage(0, mCached).sendToTarget(); - break; - } - - synchronized (mLock) { - if (mBound) { - removeMessages(MSG_DISCONNECT); - sendMessage(obtainMessage(MSG_CONNECTED, mDefaultContainer)); - } else { - Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); - mContext.bindServiceAsUser(service, mDefContainerConn, - Context.BIND_AUTO_CREATE, UserHandle.OWNER); - } - } - break; - } - case MSG_CONNECTED: { - final IMediaContainerService imcs = (IMediaContainerService) msg.obj; - measureExactStorage(imcs); - break; - } - case MSG_DISCONNECT: { - synchronized (mLock) { - if (mBound) { - mBound = false; - mContext.unbindService(mDefContainerConn); - } - } - break; - } - case MSG_COMPLETED: { - mCached = (MeasurementDetails) msg.obj; - mMainHandler.obtainMessage(0, mCached).sendToTarget(); - break; - } - case MSG_INVALIDATE: { - mCached = null; - break; - } - } - } - } - - private void measureExactStorage(IMediaContainerService imcs) { - final UserManager userManager = mContext.getSystemService(UserManager.class); - final PackageManager packageManager = mContext.getPackageManager(); - - final List users = userManager.getUsers(); - final int currentUser = ActivityManager.getCurrentUser(); - - final MeasurementDetails details = new MeasurementDetails(); - final Message finished = mMeasurementHandler.obtainMessage(MeasurementHandler.MSG_COMPLETED, - details); - - if (mSharedVolume != null && mSharedVolume.isMountedReadable()) { - final File basePath = mSharedVolume.getPathForUser(currentUser); - - // Measure media types for emulated storage, or for primary physical - // external volume - for (String type : sMeasureMediaTypes) { - final File path = new File(basePath, type); - final long size = getDirectorySize(imcs, path); - details.mediaSize.put(type, size); - } - - // Measure misc files not counted under media - details.miscSize = measureMisc(imcs, basePath); - - if (mSharedVolume.getType() == VolumeInfo.TYPE_EMULATED) { - // Measure total emulated storage of all users; internal apps data - // will be spliced in later - for (UserInfo user : users) { - final File userPath = mSharedVolume.getPathForUser(user.id); - final long size = getDirectorySize(imcs, userPath); - addValue(details.usersSize, user.id, size); - } - } - } - - // Measure all apps hosted on this volume for all users - if (mVolume.getType() == VolumeInfo.TYPE_PRIVATE) { - final List apps = packageManager.getInstalledApplications( - PackageManager.GET_UNINSTALLED_PACKAGES - | PackageManager.GET_DISABLED_COMPONENTS); - - final List volumeApps = new ArrayList<>(); - for (ApplicationInfo app : apps) { - if (Objects.equals(app.volumeUuid, mVolume.getFsUuid())) { - volumeApps.add(app); - } - } - - final int count = users.size() * volumeApps.size(); - if (count == 0) { - finished.sendToTarget(); - return; - } - - final StatsObserver observer = new StatsObserver( - true, details, currentUser, finished, count); - for (UserInfo user : users) { - for (ApplicationInfo app : volumeApps) { - packageManager.getPackageSizeInfo(app.packageName, user.id, observer); - } - } - - } else { - finished.sendToTarget(); - return; - } - } - - private static long getDirectorySize(IMediaContainerService imcs, File path) { - try { - final long size = imcs.calculateDirectorySize(path.toString()); - Log.d(TAG, "getDirectorySize(" + path + ") returned " + size); - return size; - } catch (Exception e) { - Log.w(TAG, "Could not read memory from default container service for " + path, e); - return 0; - } - } - - private long measureMisc(IMediaContainerService imcs, File dir) { - final File[] files = dir.listFiles(); - if (ArrayUtils.isEmpty(files)) return 0; - - // Get sizes of all top level nodes except the ones already computed - long miscSize = 0; - for (File file : files) { - final String name = file.getName(); - if (sMeasureMediaTypes.contains(name)) { - continue; - } - - if (file.isFile()) { - miscSize += file.length(); - } else if (file.isDirectory()) { - miscSize += getDirectorySize(imcs, file); - } - } - return miscSize; - } - - private static void addValue(SparseLongArray array, int key, long value) { - array.put(key, array.get(key) + value); - } -}