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
17package android.app.usage;
18
19import static android.os.storage.StorageManager.convert;
20
21import android.annotation.BytesLong;
22import android.annotation.NonNull;
23import android.annotation.SystemService;
24import android.annotation.TestApi;
25import android.annotation.WorkerThread;
26import android.content.Context;
27import android.content.pm.ApplicationInfo;
28import android.content.pm.PackageInfo;
29import android.content.pm.PackageManager;
30import android.os.ParcelableException;
31import android.os.RemoteException;
32import android.os.UserHandle;
33import android.os.storage.StorageManager;
34
35import com.android.internal.util.Preconditions;
36
37import java.io.File;
38import java.io.IOException;
39import 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)
55public class StorageStatsManager {
56    private final Context mContext;
57    private final IStorageStatsManager mService;
58
59    /** {@hide} */
60    public StorageStatsManager(Context context, IStorageStatsManager service) {
61        mContext = Preconditions.checkNotNull(context);
62        mService = Preconditions.checkNotNull(service);
63    }
64
65    /** {@hide} */
66    @TestApi
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
77    public boolean isQuotaSupported(String uuid) {
78        return isQuotaSupported(convert(uuid));
79    }
80
81    /** {@hide} */
82    @TestApi
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
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
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
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
152    public long getFreeBytes(String uuid) throws IOException {
153        return getFreeBytes(convert(uuid));
154    }
155
156    /** {@hide} */
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
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
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
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
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
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
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
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
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
337    public ExternalStorageStats queryExternalStatsForUser(String uuid, UserHandle user)
338            throws IOException {
339        return queryExternalStatsForUser(convert(uuid), user);
340    }
341
342    /** {@hide} */
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