1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app.usage;
18 
19 import static android.os.storage.StorageManager.convert;
20 
21 import android.annotation.BytesLong;
22 import android.annotation.NonNull;
23 import android.annotation.SystemService;
24 import android.annotation.TestApi;
25 import android.annotation.WorkerThread;
26 import android.content.Context;
27 import android.content.pm.ApplicationInfo;
28 import android.content.pm.PackageInfo;
29 import android.content.pm.PackageManager;
30 import android.os.ParcelableException;
31 import android.os.RemoteException;
32 import android.os.UserHandle;
33 import android.os.storage.StorageManager;
34 
35 import com.android.internal.util.Preconditions;
36 
37 import java.io.File;
38 import java.io.IOException;
39 import java.util.UUID;
40 
41 /**
42  * Access to detailed storage statistics. This provides a summary of how apps,
43  * users, and external/shared storage is utilizing disk space.
44  * <p class="note">
45  * Note: no permissions are required when calling these APIs for your own
46  * package or UID. However, requesting details for any other package requires
47  * the {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
48  * is a system-level permission that will not be granted to normal apps.
49  * Declaring that permission expresses your intention to use this API and an end
50  * user can then choose to grant this permission through the Settings
51  * application.
52  * </p>
53  */
54 @SystemService(Context.STORAGE_STATS_SERVICE)
55 public class StorageStatsManager {
56     private final Context mContext;
57     private final IStorageStatsManager mService;
58 
59     /** {@hide} */
StorageStatsManager(Context context, IStorageStatsManager service)60     public StorageStatsManager(Context context, IStorageStatsManager service) {
61         mContext = Preconditions.checkNotNull(context);
62         mService = Preconditions.checkNotNull(service);
63     }
64 
65     /** {@hide} */
66     @TestApi
isQuotaSupported(@onNull UUID storageUuid)67     public boolean isQuotaSupported(@NonNull UUID storageUuid) {
68         try {
69             return mService.isQuotaSupported(convert(storageUuid), mContext.getOpPackageName());
70         } catch (RemoteException e) {
71             throw e.rethrowFromSystemServer();
72         }
73     }
74 
75     /** @removed */
76     @Deprecated
isQuotaSupported(String uuid)77     public boolean isQuotaSupported(String uuid) {
78         return isQuotaSupported(convert(uuid));
79     }
80 
81     /** {@hide} */
82     @TestApi
isReservedSupported(@onNull UUID storageUuid)83     public boolean isReservedSupported(@NonNull UUID storageUuid) {
84         try {
85             return mService.isReservedSupported(convert(storageUuid), mContext.getOpPackageName());
86         } catch (RemoteException e) {
87             throw e.rethrowFromSystemServer();
88         }
89     }
90 
91     /**
92      * Return the total size of the underlying physical media that is hosting
93      * this storage volume.
94      * <p>
95      * This value is best suited for visual display to end users, since it's
96      * designed to reflect the total storage size advertised in a retail
97      * environment.
98      * <p>
99      * Apps making logical decisions about disk space should always use
100      * {@link File#getTotalSpace()} instead of this value.
101      *
102      * @param storageUuid the UUID of the storage volume you're interested in,
103      *            such as {@link StorageManager#UUID_DEFAULT}.
104      * @throws IOException when the storage device isn't present.
105      */
106     @WorkerThread
getTotalBytes(@onNull UUID storageUuid)107     public @BytesLong long getTotalBytes(@NonNull UUID storageUuid) throws IOException {
108         try {
109             return mService.getTotalBytes(convert(storageUuid), mContext.getOpPackageName());
110         } catch (ParcelableException e) {
111             e.maybeRethrow(IOException.class);
112             throw new RuntimeException(e);
113         } catch (RemoteException e) {
114             throw e.rethrowFromSystemServer();
115         }
116     }
117 
118     /** @removed */
119     @Deprecated
getTotalBytes(String uuid)120     public long getTotalBytes(String uuid) throws IOException {
121         return getTotalBytes(convert(uuid));
122     }
123 
124     /**
125      * Return the free space on the requested storage volume.
126      * <p>
127      * This value is best suited for visual display to end users, since it's
128      * designed to reflect both unused space <em>and</em> and cached space that
129      * could be reclaimed by the system.
130      * <p>
131      * Apps making logical decisions about disk space should always use
132      * {@link StorageManager#getAllocatableBytes(UUID)} instead of this value.
133      *
134      * @param storageUuid the UUID of the storage volume you're interested in,
135      *            such as {@link StorageManager#UUID_DEFAULT}.
136      * @throws IOException when the storage device isn't present.
137      */
138     @WorkerThread
getFreeBytes(@onNull UUID storageUuid)139     public @BytesLong long getFreeBytes(@NonNull UUID storageUuid) throws IOException {
140         try {
141             return mService.getFreeBytes(convert(storageUuid), mContext.getOpPackageName());
142         } catch (ParcelableException e) {
143             e.maybeRethrow(IOException.class);
144             throw new RuntimeException(e);
145         } catch (RemoteException e) {
146             throw e.rethrowFromSystemServer();
147         }
148     }
149 
150     /** @removed */
151     @Deprecated
getFreeBytes(String uuid)152     public long getFreeBytes(String uuid) throws IOException {
153         return getFreeBytes(convert(uuid));
154     }
155 
156     /** {@hide} */
getCacheBytes(@onNull UUID storageUuid)157     public @BytesLong long getCacheBytes(@NonNull UUID storageUuid) throws IOException {
158         try {
159             return mService.getCacheBytes(convert(storageUuid), mContext.getOpPackageName());
160         } catch (ParcelableException e) {
161             e.maybeRethrow(IOException.class);
162             throw new RuntimeException(e);
163         } catch (RemoteException e) {
164             throw e.rethrowFromSystemServer();
165         }
166     }
167 
168     /** {@hide} */
169     @Deprecated
getCacheBytes(String uuid)170     public long getCacheBytes(String uuid) throws IOException {
171         return getCacheBytes(convert(uuid));
172     }
173 
174     /**
175      * Return storage statistics for a specific package on the requested storage
176      * volume.
177      * <p class="note">
178      * Note: no permissions are required when calling this API for your own
179      * package. However, requesting details for any other package requires the
180      * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
181      * is a system-level permission that will not be granted to normal apps.
182      * Declaring that permission expresses your intention to use this API and an
183      * end user can then choose to grant this permission through the Settings
184      * application.
185      * </p>
186      * <p class="note">
187      * Note: if the requested package uses the {@code android:sharedUserId}
188      * manifest feature, this call will be forced into a slower manual
189      * calculation path. If possible, consider always using
190      * {@link #queryStatsForUid(UUID, int)}, which is typically faster.
191      * </p>
192      *
193      * @param storageUuid the UUID of the storage volume you're interested in,
194      *            such as {@link StorageManager#UUID_DEFAULT}.
195      * @param packageName the package name you're interested in.
196      * @param user the user you're interested in.
197      * @throws PackageManager.NameNotFoundException when the requested package
198      *             name isn't installed for the requested user.
199      * @throws IOException when the storage device isn't present.
200      * @see ApplicationInfo#storageUuid
201      * @see PackageInfo#packageName
202      */
203     @WorkerThread
queryStatsForPackage(@onNull UUID storageUuid, @NonNull String packageName, @NonNull UserHandle user)204     public @NonNull StorageStats queryStatsForPackage(@NonNull UUID storageUuid,
205             @NonNull String packageName, @NonNull UserHandle user)
206             throws PackageManager.NameNotFoundException, IOException {
207         try {
208             return mService.queryStatsForPackage(convert(storageUuid), packageName,
209                     user.getIdentifier(), mContext.getOpPackageName());
210         } catch (ParcelableException e) {
211             e.maybeRethrow(PackageManager.NameNotFoundException.class);
212             e.maybeRethrow(IOException.class);
213             throw new RuntimeException(e);
214         } catch (RemoteException e) {
215             throw e.rethrowFromSystemServer();
216         }
217     }
218 
219     /** @removed */
220     @Deprecated
queryStatsForPackage(String uuid, String packageName, UserHandle user)221     public StorageStats queryStatsForPackage(String uuid, String packageName,
222             UserHandle user) throws PackageManager.NameNotFoundException, IOException {
223         return queryStatsForPackage(convert(uuid), packageName, user);
224     }
225 
226     /**
227      * Return storage statistics for a specific UID on the requested storage
228      * volume.
229      * <p class="note">
230      * Note: no permissions are required when calling this API for your own UID.
231      * However, requesting details for any other UID requires the
232      * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
233      * is a system-level permission that will not be granted to normal apps.
234      * Declaring that permission expresses your intention to use this API and an
235      * end user can then choose to grant this permission through the Settings
236      * application.
237      * </p>
238      *
239      * @param storageUuid the UUID of the storage volume you're interested in,
240      *            such as {@link StorageManager#UUID_DEFAULT}.
241      * @param uid the UID you're interested in.
242      * @throws IOException when the storage device isn't present.
243      * @see ApplicationInfo#storageUuid
244      * @see ApplicationInfo#uid
245      */
246     @WorkerThread
queryStatsForUid(@onNull UUID storageUuid, int uid)247     public @NonNull StorageStats queryStatsForUid(@NonNull UUID storageUuid, int uid)
248             throws IOException {
249         try {
250             return mService.queryStatsForUid(convert(storageUuid), uid,
251                     mContext.getOpPackageName());
252         } catch (ParcelableException e) {
253             e.maybeRethrow(IOException.class);
254             throw new RuntimeException(e);
255         } catch (RemoteException e) {
256             throw e.rethrowFromSystemServer();
257         }
258     }
259 
260     /** @removed */
261     @Deprecated
queryStatsForUid(String uuid, int uid)262     public StorageStats queryStatsForUid(String uuid, int uid) throws IOException {
263         return queryStatsForUid(convert(uuid), uid);
264     }
265 
266     /**
267      * Return storage statistics for a specific {@link UserHandle} on the
268      * requested storage volume.
269      * <p class="note">
270      * Note: this API requires the
271      * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
272      * is a system-level permission that will not be granted to normal apps.
273      * Declaring that permission expresses your intention to use this API and an
274      * end user can then choose to grant this permission through the Settings
275      * application.
276      * </p>
277      *
278      * @param storageUuid the UUID of the storage volume you're interested in,
279      *            such as {@link StorageManager#UUID_DEFAULT}.
280      * @param user the user you're interested in.
281      * @throws IOException when the storage device isn't present.
282      * @see android.os.Process#myUserHandle()
283      */
284     @WorkerThread
queryStatsForUser(@onNull UUID storageUuid, @NonNull UserHandle user)285     public @NonNull StorageStats queryStatsForUser(@NonNull UUID storageUuid,
286             @NonNull UserHandle user) throws IOException {
287         try {
288             return mService.queryStatsForUser(convert(storageUuid), user.getIdentifier(),
289                     mContext.getOpPackageName());
290         } catch (ParcelableException e) {
291             e.maybeRethrow(IOException.class);
292             throw new RuntimeException(e);
293         } catch (RemoteException e) {
294             throw e.rethrowFromSystemServer();
295         }
296     }
297 
298     /** @removed */
299     @Deprecated
queryStatsForUser(String uuid, UserHandle user)300     public StorageStats queryStatsForUser(String uuid, UserHandle user) throws IOException {
301         return queryStatsForUser(convert(uuid), user);
302     }
303 
304     /**
305      * Return shared/external storage statistics for a specific
306      * {@link UserHandle} on the requested storage volume.
307      * <p class="note">
308      * Note: this API requires the
309      * {@code android.Manifest.permission#PACKAGE_USAGE_STATS} permission, which
310      * is a system-level permission that will not be granted to normal apps.
311      * Declaring that permission expresses your intention to use this API and an
312      * end user can then choose to grant this permission through the Settings
313      * application.
314      * </p>
315      *
316      * @param storageUuid the UUID of the storage volume you're interested in,
317      *            such as {@link StorageManager#UUID_DEFAULT}.
318      * @throws IOException when the storage device isn't present.
319      * @see android.os.Process#myUserHandle()
320      */
321     @WorkerThread
queryExternalStatsForUser(@onNull UUID storageUuid, @NonNull UserHandle user)322     public @NonNull ExternalStorageStats queryExternalStatsForUser(@NonNull UUID storageUuid,
323             @NonNull UserHandle user) throws IOException {
324         try {
325             return mService.queryExternalStatsForUser(convert(storageUuid), user.getIdentifier(),
326                     mContext.getOpPackageName());
327         } catch (ParcelableException e) {
328             e.maybeRethrow(IOException.class);
329             throw new RuntimeException(e);
330         } catch (RemoteException e) {
331             throw e.rethrowFromSystemServer();
332         }
333     }
334 
335     /** @removed */
336     @Deprecated
queryExternalStatsForUser(String uuid, UserHandle user)337     public ExternalStorageStats queryExternalStatsForUser(String uuid, UserHandle user)
338             throws IOException {
339         return queryExternalStatsForUser(convert(uuid), user);
340     }
341 
342     /** {@hide} */
getCacheQuotaBytes(String volumeUuid, int uid)343     public long getCacheQuotaBytes(String volumeUuid, int uid) {
344         try {
345             return mService.getCacheQuotaBytes(volumeUuid, uid, mContext.getOpPackageName());
346         } catch (RemoteException e) {
347             throw e.rethrowFromSystemServer();
348         }
349     }
350 }
351