content: /*
   * Copyright (C) 2017 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 android.app.usage;
  
  import static android.os.storage.StorageManager.convert;
  
  import android.annotation.BytesLong;
  import android.annotation.NonNull;
  import android.annotation.SystemService;
  import android.annotation.TestApi;
  import android.annotation.WorkerThread;
  import android.content.Context;
  import android.content.pm.ApplicationInfo;
  import android.content.pm.PackageInfo;
  import android.content.pm.PackageManager;
  import android.os.ParcelableException;
  import android.os.RemoteException;
  import android.os.UserHandle;
  import android.os.storage.StorageManager;
  
  import com.android.internal.util.Preconditions;
  
  import java.io.File;
  import java.io.IOException;
  import java.util.UUID;
  
  /**
   * Access to detailed storage statistics. This provides a summary of how apps,
   * users, and external/shared storage is utilizing disk space.
   * <p class="note">
   * Note: no permissions are required when calling these APIs for your own
   * package or UID. However, requesting details for any other package requires
   * the {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
   * is a system-level permission that will not be granted to normal apps.
   * Declaring that permission expresses your intention to use this API and an end
   * user can then choose to grant this permission through the Settings
   * application.
   * </p>
   */
  @SystemService(Context.STORAGE_STATS_SERVICE)
  public class StorageStatsManager {
      private final Context mContext;
      private final IStorageStatsManager mService;
  
      /** {@hide} */
      public StorageStatsManager(Context context, IStorageStatsManager service) {
          mContext = Preconditions.checkNotNull(context);
          mService = Preconditions.checkNotNull(service);
      }
  
      /** {@hide} */
      @TestApi
      public boolean isQuotaSupported(@NonNull UUID storageUuid) {
          try {
              return mService.isQuotaSupported(convert(storageUuid), mContext.getOpPackageName());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** @removed */
      @Deprecated
      public boolean isQuotaSupported(String uuid) {
          return isQuotaSupported(convert(uuid));
      }
  
      /** {@hide} */
      @TestApi
      public boolean isReservedSupported(@NonNull UUID storageUuid) {
          try {
              return mService.isReservedSupported(convert(storageUuid), mContext.getOpPackageName());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /**
       * Return the total size of the underlying physical media that is hosting
       * this storage volume.
       * <p>
       * This value is best suited for visual display to end users, since it's
       * designed to reflect the total storage size advertised in a retail
       * environment.
       * <p>
       * Apps making logical decisions about disk space should always use
       * {@link File#getTotalSpace()} instead of this value.
       *
       * @param storageUuid the UUID of the storage volume you're interested in,
       *            such as {@link StorageManager#UUID_DEFAULT}.
       * @throws IOException when the storage device isn't present.
       */
      @WorkerThread
      public @BytesLong long getTotalBytes(@NonNull UUID storageUuid) throws IOException {
          try {
              return mService.getTotalBytes(convert(storageUuid), mContext.getOpPackageName());
          } catch (ParcelableException e) {
              e.maybeRethrow(IOException.class);
              throw new RuntimeException(e);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** @removed */
      @Deprecated
      public long getTotalBytes(String uuid) throws IOException {
          return getTotalBytes(convert(uuid));
      }
  
      /**
       * Return the free space on the requested storage volume.
       * <p>
       * This value is best suited for visual display to end users, since it's
       * designed to reflect both unused space <em>and</em> and cached space that
       * could be reclaimed by the system.
       * <p>
       * Apps making logical decisions about disk space should always use
       * {@link StorageManager#getAllocatableBytes(UUID)} instead of this value.
       *
       * @param storageUuid the UUID of the storage volume you're interested in,
       *            such as {@link StorageManager#UUID_DEFAULT}.
       * @throws IOException when the storage device isn't present.
       */
      @WorkerThread
      public @BytesLong long getFreeBytes(@NonNull UUID storageUuid) throws IOException {
          try {
              return mService.getFreeBytes(convert(storageUuid), mContext.getOpPackageName());
          } catch (ParcelableException e) {
              e.maybeRethrow(IOException.class);
              throw new RuntimeException(e);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** @removed */
      @Deprecated
      public long getFreeBytes(String uuid) throws IOException {
          return getFreeBytes(convert(uuid));
      }
  
      /** {@hide} */
      public @BytesLong long getCacheBytes(@NonNull UUID storageUuid) throws IOException {
          try {
              return mService.getCacheBytes(convert(storageUuid), mContext.getOpPackageName());
          } catch (ParcelableException e) {
              e.maybeRethrow(IOException.class);
              throw new RuntimeException(e);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** {@hide} */
      @Deprecated
      public long getCacheBytes(String uuid) throws IOException {
          return getCacheBytes(convert(uuid));
      }
  
      /**
       * Return storage statistics for a specific package on the requested storage
       * volume.
       * <p class="note">
       * Note: no permissions are required when calling this API for your own
       * package. However, requesting details for any other package requires the
       * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
       * is a system-level permission that will not be granted to normal apps.
       * Declaring that permission expresses your intention to use this API and an
       * end user can then choose to grant this permission through the Settings
       * application.
       * </p>
       * <p class="note">
       * Note: if the requested package uses the {@code android:sharedUserId}
       * manifest feature, this call will be forced into a slower manual
       * calculation path. If possible, consider always using
       * {@link #queryStatsForUid(UUID, int)}, which is typically faster.
       * </p>
       *
       * @param storageUuid the UUID of the storage volume you're interested in,
       *            such as {@link StorageManager#UUID_DEFAULT}.
       * @param packageName the package name you're interested in.
       * @param user the user you're interested in.
       * @throws PackageManager.NameNotFoundException when the requested package
       *             name isn't installed for the requested user.
       * @throws IOException when the storage device isn't present.
       * @see ApplicationInfo#storageUuid
       * @see PackageInfo#packageName
       */
      @WorkerThread
      public @NonNull StorageStats queryStatsForPackage(@NonNull UUID storageUuid,
              @NonNull String packageName, @NonNull UserHandle user)
              throws PackageManager.NameNotFoundException, IOException {
          try {
              return mService.queryStatsForPackage(convert(storageUuid), packageName,
                      user.getIdentifier(), mContext.getOpPackageName());
          } catch (ParcelableException e) {
              e.maybeRethrow(PackageManager.NameNotFoundException.class);
              e.maybeRethrow(IOException.class);
              throw new RuntimeException(e);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** @removed */
      @Deprecated
      public StorageStats queryStatsForPackage(String uuid, String packageName,
              UserHandle user) throws PackageManager.NameNotFoundException, IOException {
          return queryStatsForPackage(convert(uuid), packageName, user);
      }
  
      /**
       * Return storage statistics for a specific UID on the requested storage
       * volume.
       * <p class="note">
       * Note: no permissions are required when calling this API for your own UID.
       * However, requesting details for any other UID requires the
       * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
       * is a system-level permission that will not be granted to normal apps.
       * Declaring that permission expresses your intention to use this API and an
       * end user can then choose to grant this permission through the Settings
       * application.
       * </p>
       *
       * @param storageUuid the UUID of the storage volume you're interested in,
       *            such as {@link StorageManager#UUID_DEFAULT}.
       * @param uid the UID you're interested in.
       * @throws IOException when the storage device isn't present.
       * @see ApplicationInfo#storageUuid
       * @see ApplicationInfo#uid
       */
      @WorkerThread
      public @NonNull StorageStats queryStatsForUid(@NonNull UUID storageUuid, int uid)
              throws IOException {
          try {
              return mService.queryStatsForUid(convert(storageUuid), uid,
                      mContext.getOpPackageName());
          } catch (ParcelableException e) {
              e.maybeRethrow(IOException.class);
              throw new RuntimeException(e);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** @removed */
      @Deprecated
      public StorageStats queryStatsForUid(String uuid, int uid) throws IOException {
          return queryStatsForUid(convert(uuid), uid);
      }
  
      /**
       * Return storage statistics for a specific {@link UserHandle} on the
       * requested storage volume.
       * <p class="note">
       * Note: this API requires the
       * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
       * is a system-level permission that will not be granted to normal apps.
       * Declaring that permission expresses your intention to use this API and an
       * end user can then choose to grant this permission through the Settings
       * application.
       * </p>
       *
       * @param storageUuid the UUID of the storage volume you're interested in,
       *            such as {@link StorageManager#UUID_DEFAULT}.
       * @param user the user you're interested in.
       * @throws IOException when the storage device isn't present.
       * @see android.os.Process#myUserHandle()
       */
      @WorkerThread
      public @NonNull StorageStats queryStatsForUser(@NonNull UUID storageUuid,
              @NonNull UserHandle user) throws IOException {
          try {
              return mService.queryStatsForUser(convert(storageUuid), user.getIdentifier(),
                      mContext.getOpPackageName());
          } catch (ParcelableException e) {
              e.maybeRethrow(IOException.class);
              throw new RuntimeException(e);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** @removed */
      @Deprecated
      public StorageStats queryStatsForUser(String uuid, UserHandle user) throws IOException {
          return queryStatsForUser(convert(uuid), user);
      }
  
      /**
       * Return shared/external storage statistics for a specific
       * {@link UserHandle} on the requested storage volume.
       * <p class="note">
       * Note: this API requires the
       * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
       * is a system-level permission that will not be granted to normal apps.
       * Declaring that permission expresses your intention to use this API and an
       * end user can then choose to grant this permission through the Settings
       * application.
       * </p>
       *
       * @param storageUuid the UUID of the storage volume you're interested in,
       *            such as {@link StorageManager#UUID_DEFAULT}.
       * @throws IOException when the storage device isn't present.
       * @see android.os.Process#myUserHandle()
       */
      @WorkerThread
      public @NonNull ExternalStorageStats queryExternalStatsForUser(@NonNull UUID storageUuid,
              @NonNull UserHandle user) throws IOException {
          try {
              return mService.queryExternalStatsForUser(convert(storageUuid), user.getIdentifier(),
                      mContext.getOpPackageName());
          } catch (ParcelableException e) {
              e.maybeRethrow(IOException.class);
              throw new RuntimeException(e);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  
      /** @removed */
      @Deprecated
      public ExternalStorageStats queryExternalStatsForUser(String uuid, UserHandle user)
              throws IOException {
          return queryExternalStatsForUser(convert(uuid), user);
      }
  
      /** {@hide} */
      public long getCacheQuotaBytes(String volumeUuid, int uid) {
          try {
              return mService.getCacheQuotaBytes(volumeUuid, uid, mContext.getOpPackageName());
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }
  }
  