blob: 27e391423d218b1dc8f188fd428a32f02a158a52 [file] [log] [blame]
San Mehatb1043402010-02-05 08:26:50 -08001/*
2 * Copyright (C) 2008 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.os.storage;
18
Jeff Sharkeya4d34d92017-04-27 11:21:41 -060019import android.annotation.BytesLong;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -070020import android.annotation.IntDef;
Jeff Sharkey48877892015-03-18 11:27:19 -070021import android.annotation.NonNull;
22import android.annotation.Nullable;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -070023import android.annotation.RequiresPermission;
Daniel Nishi690346b2016-06-17 10:21:48 -070024import android.annotation.SdkConstant;
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -060025import android.annotation.SuppressLint;
Jeff Sharkeya4d34d92017-04-27 11:21:41 -060026import android.annotation.SystemApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060027import android.annotation.SystemService;
Jeff Sharkey10ec9d82018-11-28 14:52:45 -070028import android.annotation.TestApi;
Mathew Inwood98e9ad12018-08-30 13:11:50 +010029import android.annotation.UnsupportedAppUsage;
Jeff Sharkeya4d34d92017-04-27 11:21:41 -060030import android.annotation.WorkerThread;
Jeff Sharkeyb31afd22017-06-12 14:17:10 -060031import android.app.Activity;
Svet Ganov6ee871e2015-07-10 14:29:33 -070032import android.app.ActivityThread;
Jeff Sharkeybe722152013-02-15 16:56:38 -080033import android.content.ContentResolver;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070034import android.content.Context;
Jeff Sharkeya4d34d92017-04-27 11:21:41 -060035import android.content.Intent;
Jeff Sharkey9bed0702017-01-23 20:37:05 -070036import android.content.pm.ApplicationInfo;
Jeff Sharkey275e3e42015-04-24 16:10:32 -070037import android.content.pm.IPackageMoveObserver;
38import android.content.pm.PackageManager;
Sudheer Shanka25469aa2018-08-27 15:50:23 -070039import android.content.res.ObbInfo;
40import android.content.res.ObbScanner;
Jeff Sharkeyf8fa9402019-02-18 13:23:51 -070041import android.net.Uri;
Jeff Sharkeyce18c812016-04-27 16:00:41 -060042import android.os.Binder;
Mike Lockwoodcba928c2011-08-17 15:58:52 -070043import android.os.Environment;
Jeff Sharkey48877892015-03-18 11:27:19 -070044import android.os.FileUtils;
San Mehatb1043402010-02-05 08:26:50 -080045import android.os.Handler;
Jeff Sharkey4e7a7652018-08-24 17:25:42 -060046import android.os.IInstalld;
Jeff Sharkey41cd6812017-09-11 10:32:17 -060047import android.os.IVold;
Jeff Sharkey7e19f532017-11-06 13:54:11 -070048import android.os.IVoldTaskListener;
Kenny Roota02b8b02010-08-05 16:14:17 -070049import android.os.Looper;
San Mehatb1043402010-02-05 08:26:50 -080050import android.os.Message;
Daichi Hirono9e8d9e22015-11-13 14:37:00 +090051import android.os.ParcelFileDescriptor;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -070052import android.os.ParcelableException;
Jeff Sharkey7e19f532017-11-06 13:54:11 -070053import android.os.PersistableBundle;
Jeff Sharkey9bed0702017-01-23 20:37:05 -070054import android.os.ProxyFileDescriptorCallback;
Kenny Roota02b8b02010-08-05 16:14:17 -070055import android.os.RemoteException;
San Mehatb1043402010-02-05 08:26:50 -080056import android.os.ServiceManager;
Jeff Sharkey49ca5292016-05-10 12:54:45 -060057import android.os.ServiceManager.ServiceNotFoundException;
Jeff Sharkeyba512352015-11-12 20:17:45 -080058import android.os.SystemProperties;
Jeff Sharkeyf8fa9402019-02-18 13:23:51 -070059import android.provider.MediaStore;
Jeff Sharkeybe722152013-02-15 16:56:38 -080060import android.provider.Settings;
Inseob Kimc1246e62018-11-08 13:13:54 +090061import android.sysprop.VoldProperties;
Jeff Sharkey9bed0702017-01-23 20:37:05 -070062import android.system.ErrnoException;
63import android.system.Os;
64import android.system.OsConstants;
Jeff Sharkey59d577a2015-04-11 21:27:21 -070065import android.text.TextUtils;
Jeff Sharkey9f2dc052018-01-07 16:47:31 -070066import android.util.DataUnit;
San Mehatb1043402010-02-05 08:26:50 -080067import android.util.Log;
Felipe Leme281389a2016-10-10 17:12:20 -070068import android.util.Pair;
Jeff Sharkeyb42d6942015-04-28 22:25:26 -070069import android.util.Slog;
Kenny Rootaf9d6672010-10-08 09:21:39 -070070import android.util.SparseArray;
Jeff Sharkey9bed0702017-01-23 20:37:05 -070071
Daichi Hirono9fb00182016-11-08 14:12:17 +090072import com.android.internal.annotations.GuardedBy;
73import com.android.internal.annotations.VisibleForTesting;
Daichi Hironod61817e2017-02-13 10:37:11 +090074import com.android.internal.logging.MetricsLogger;
Daichi Hirono9fb00182016-11-08 14:12:17 +090075import com.android.internal.os.AppFuseMount;
76import com.android.internal.os.FuseAppLoop;
Daichi Hirono812c95d2017-02-08 16:20:20 +090077import com.android.internal.os.FuseUnavailableMountException;
John Reckaa67f682016-09-20 14:24:21 -070078import com.android.internal.os.RoSystemProperties;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070079import com.android.internal.os.SomeArgs;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -070080import com.android.internal.util.Preconditions;
81
Jeff Sharkeydd02e332018-06-27 14:41:57 -060082import dalvik.system.BlockGuard;
83
Jeff Sharkey4fbbda42012-09-24 18:34:07 -070084import java.io.File;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -070085import java.io.FileDescriptor;
Jeff Sharkey789a8fc2017-04-16 13:18:35 -060086import java.io.FileNotFoundException;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -070087import java.io.IOException;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -070088import java.lang.annotation.Retention;
89import java.lang.annotation.RetentionPolicy;
Kenny Root05105f72010-09-22 17:29:43 -070090import java.lang.ref.WeakReference;
Jeff Sharkey9bed0702017-01-23 20:37:05 -070091import java.nio.charset.StandardCharsets;
San Mehatb1043402010-02-05 08:26:50 -080092import java.util.ArrayList;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070093import java.util.Arrays;
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -060094import java.util.Collections;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070095import java.util.Iterator;
Kenny Root05105f72010-09-22 17:29:43 -070096import java.util.List;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070097import java.util.Objects;
Jeff Sharkey789a8fc2017-04-16 13:18:35 -060098import java.util.UUID;
Jeff Sharkey7e19f532017-11-06 13:54:11 -070099import java.util.concurrent.CompletableFuture;
Daichi Hirono9fb00182016-11-08 14:12:17 +0900100import java.util.concurrent.ThreadFactory;
Jeff Sharkey7e19f532017-11-06 13:54:11 -0700101import java.util.concurrent.TimeUnit;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700102import java.util.concurrent.atomic.AtomicInteger;
San Mehatb1043402010-02-05 08:26:50 -0800103
104/**
Kenny Root05105f72010-09-22 17:29:43 -0700105 * StorageManager is the interface to the systems storage service. The storage
106 * manager handles storage-related items such as Opaque Binary Blobs (OBBs).
107 * <p>
108 * OBBs contain a filesystem that maybe be encrypted on disk and mounted
109 * on-demand from an application. OBBs are a good way of providing large amounts
110 * of binary assets without packaging them into APKs as they may be multiple
111 * gigabytes in size. However, due to their size, they're most likely stored in
112 * a shared storage pool accessible from all programs. The system does not
113 * guarantee the security of the OBB file itself: if any program modifies the
114 * OBB, there is no guarantee that a read from that OBB will produce the
115 * expected output.
San Mehatb1043402010-02-05 08:26:50 -0800116 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600117@SystemService(Context.STORAGE_SERVICE)
Jeff Sharkeybe722152013-02-15 16:56:38 -0800118public class StorageManager {
San Mehatb1043402010-02-05 08:26:50 -0800119 private static final String TAG = "StorageManager";
120
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700121 /** {@hide} */
122 public static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical";
Jeff Sharkey74acbbb2015-04-21 12:14:03 -0700123 /** {@hide} */
Jeff Sharkey0d838a02015-05-13 13:54:30 -0700124 public static final String PROP_HAS_ADOPTABLE = "vold.has_adoptable";
125 /** {@hide} */
Jeff Sharkey55fe0d02018-01-08 10:41:47 -0700126 public static final String PROP_HAS_RESERVED = "vold.has_reserved";
127 /** {@hide} */
Jeff Sharkey901c0422018-04-20 13:11:20 -0600128 public static final String PROP_ADOPTABLE = "persist.sys.adoptable";
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800129 /** {@hide} */
Jeff Sharkeyba512352015-11-12 20:17:45 -0800130 public static final String PROP_EMULATE_FBE = "persist.sys.emulate_fbe";
Jeff Sharkey33dd1562016-04-07 11:05:33 -0600131 /** {@hide} */
132 public static final String PROP_SDCARDFS = "persist.sys.sdcardfs";
Jeff Sharkeye53e2d92017-03-25 23:14:06 -0600133 /** {@hide} */
134 public static final String PROP_VIRTUAL_DISK = "persist.sys.virtual_disk";
Jeff Sharkey4aacd8b2018-07-24 15:24:21 -0600135 /** {@hide} */
136 public static final String PROP_ISOLATED_STORAGE = "persist.sys.isolated_storage";
Jeff Sharkey342b4bf2018-12-18 11:12:40 -0700137 /** {@hide} */
138 public static final String PROP_ISOLATED_STORAGE_SNAPSHOT = "sys.isolated_storage_snapshot";
Jeff Sharkey36274992019-02-27 12:09:57 -0700139 /** {@hide} */
140 public static final String PROP_LEGACY_GREYLIST = "persist.sys.legacy_greylist";
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700141
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700142 /** {@hide} */
Jeff Sharkey669e6b12018-10-27 17:58:44 -0600143 public static final String PROP_FORCE_AUDIO = "persist.fw.force_audio";
144 /** {@hide} */
145 public static final String PROP_FORCE_VIDEO = "persist.fw.force_video";
146 /** {@hide} */
147 public static final String PROP_FORCE_IMAGES = "persist.fw.force_images";
Jeff Sharkey669e6b12018-10-27 17:58:44 -0600148
149 /** {@hide} */
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700150 public static final String UUID_PRIVATE_INTERNAL = null;
151 /** {@hide} */
152 public static final String UUID_PRIMARY_PHYSICAL = "primary_physical";
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600153 /** {@hide} */
154 public static final String UUID_SYSTEM = "system";
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700155
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600156 // NOTE: UUID constants below are namespaced
157 // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad default
158 // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad primary_physical
159 // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad system
Daniel Nishi690346b2016-06-17 10:21:48 -0700160
161 /**
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600162 * UUID representing the default internal storage of this device which
163 * provides {@link Environment#getDataDirectory()}.
Daniel Nishi690346b2016-06-17 10:21:48 -0700164 * <p>
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600165 * This value is constant across all devices and it will never change, and
166 * thus it cannot be used to uniquely identify a particular physical device.
167 *
168 * @see #getUuidForPath(File)
Jeff Sharkeya4d34d92017-04-27 11:21:41 -0600169 * @see ApplicationInfo#storageUuid
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600170 */
171 public static final UUID UUID_DEFAULT = UUID
172 .fromString("41217664-9172-527a-b3d5-edabb50a7d69");
173
174 /** {@hide} */
175 public static final UUID UUID_PRIMARY_PHYSICAL_ = UUID
176 .fromString("0f95a519-dae7-5abf-9519-fbd6209e05fd");
177
178 /** {@hide} */
179 public static final UUID UUID_SYSTEM_ = UUID
180 .fromString("5d258386-e60d-59e3-826d-0089cdd42cc0");
181
182 /**
183 * Activity Action: Allows the user to manage their storage. This activity
184 * provides the ability to free up space on the device by deleting data such
185 * as apps.
Daniel Nishi690346b2016-06-17 10:21:48 -0700186 * <p>
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600187 * If the sending application has a specific storage device or allocation
188 * size in mind, they can optionally define {@link #EXTRA_UUID} or
189 * {@link #EXTRA_REQUESTED_BYTES}, respectively.
Jeff Sharkeyb31afd22017-06-12 14:17:10 -0600190 * <p>
191 * This intent should be launched using
192 * {@link Activity#startActivityForResult(Intent, int)} so that the user
193 * knows which app is requesting the storage space. The returned result will
194 * be {@link Activity#RESULT_OK} if the requested space was made available,
195 * or {@link Activity#RESULT_CANCELED} otherwise.
Daniel Nishi690346b2016-06-17 10:21:48 -0700196 */
197 @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600198 public static final String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
199
200 /**
201 * Extra {@link UUID} used to indicate the storage volume where an
202 * application is interested in allocating or managing disk space.
203 *
204 * @see #ACTION_MANAGE_STORAGE
205 * @see #UUID_DEFAULT
206 * @see #getUuidForPath(File)
Jeff Sharkeya4d34d92017-04-27 11:21:41 -0600207 * @see Intent#putExtra(String, java.io.Serializable)
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600208 */
209 public static final String EXTRA_UUID = "android.os.storage.extra.UUID";
210
211 /**
212 * Extra used to indicate the total size (in bytes) that an application is
213 * interested in allocating.
214 * <p>
215 * When defined, the management UI will help guide the user to free up
216 * enough disk space to reach this requested value.
217 *
218 * @see #ACTION_MANAGE_STORAGE
219 */
220 public static final String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES";
Daniel Nishi690346b2016-06-17 10:21:48 -0700221
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700222 /** {@hide} */
Jeff Sharkey901c0422018-04-20 13:11:20 -0600223 public static final int DEBUG_ADOPTABLE_FORCE_ON = 1 << 0;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800224 /** {@hide} */
Jeff Sharkey901c0422018-04-20 13:11:20 -0600225 public static final int DEBUG_ADOPTABLE_FORCE_OFF = 1 << 1;
Jeff Sharkey33dd1562016-04-07 11:05:33 -0600226 /** {@hide} */
Jeff Sharkey901c0422018-04-20 13:11:20 -0600227 public static final int DEBUG_EMULATE_FBE = 1 << 2;
Jeff Sharkey33dd1562016-04-07 11:05:33 -0600228 /** {@hide} */
Jeff Sharkey901c0422018-04-20 13:11:20 -0600229 public static final int DEBUG_SDCARDFS_FORCE_ON = 1 << 3;
Jeff Sharkeye53e2d92017-03-25 23:14:06 -0600230 /** {@hide} */
Jeff Sharkey901c0422018-04-20 13:11:20 -0600231 public static final int DEBUG_SDCARDFS_FORCE_OFF = 1 << 4;
232 /** {@hide} */
233 public static final int DEBUG_VIRTUAL_DISK = 1 << 5;
Sudheer Shankabe0febe2018-11-07 18:24:37 -0800234 /** {@hide} */
Jeff Sharkeyb0c363b22018-12-15 11:53:03 -0700235 public static final int DEBUG_ISOLATED_STORAGE_FORCE_ON = 1 << 6;
236 /** {@hide} */
237 public static final int DEBUG_ISOLATED_STORAGE_FORCE_OFF = 1 << 7;
Jeff Sharkey36274992019-02-27 12:09:57 -0700238 /** {@hide} */
239 public static final int DEBUG_LEGACY_GREYLIST = 1 << 8;
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700240
Jeff Sharkey46349872015-07-28 10:49:47 -0700241 /** {@hide} */
Jeff Sharkey4e7a7652018-08-24 17:25:42 -0600242 public static final int FLAG_STORAGE_DE = IInstalld.FLAG_STORAGE_DE;
Jeff Sharkey47f71082016-02-01 17:03:54 -0700243 /** {@hide} */
Jeff Sharkey4e7a7652018-08-24 17:25:42 -0600244 public static final int FLAG_STORAGE_CE = IInstalld.FLAG_STORAGE_CE;
Jeff Sharkey47f71082016-02-01 17:03:54 -0700245
246 /** {@hide} */
247 public static final int FLAG_FOR_WRITE = 1 << 8;
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -0600248 /** {@hide} */
249 public static final int FLAG_REAL_STATE = 1 << 9;
250 /** {@hide} */
251 public static final int FLAG_INCLUDE_INVISIBLE = 1 << 10;
Jeff Sharkey46349872015-07-28 10:49:47 -0700252
Jeff Sharkey31d0b702016-11-21 14:16:53 -0700253 /** {@hide} */
Jeff Sharkey41cd6812017-09-11 10:32:17 -0600254 public static final int FSTRIM_FLAG_DEEP = IVold.FSTRIM_FLAG_DEEP_TRIM;
Jeff Sharkey31d0b702016-11-21 14:16:53 -0700255
Sudheer Shankaf7341142016-10-18 17:15:18 -0700256 /** @hide The volume is not encrypted. */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100257 @UnsupportedAppUsage
Jeff Sharkey43e12112017-09-12 16:31:45 -0600258 public static final int ENCRYPTION_STATE_NONE =
259 IVold.ENCRYPTION_STATE_NONE;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700260
261 /** @hide The volume has been encrypted succesfully. */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600262 public static final int ENCRYPTION_STATE_OK =
263 IVold.ENCRYPTION_STATE_OK;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700264
Jeff Sharkey43e12112017-09-12 16:31:45 -0600265 /** @hide The volume is in a bad state. */
266 public static final int ENCRYPTION_STATE_ERROR_UNKNOWN =
267 IVold.ENCRYPTION_STATE_ERROR_UNKNOWN;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700268
269 /** @hide Encryption is incomplete */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600270 public static final int ENCRYPTION_STATE_ERROR_INCOMPLETE =
271 IVold.ENCRYPTION_STATE_ERROR_INCOMPLETE;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700272
273 /** @hide Encryption is incomplete and irrecoverable */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600274 public static final int ENCRYPTION_STATE_ERROR_INCONSISTENT =
275 IVold.ENCRYPTION_STATE_ERROR_INCONSISTENT;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700276
277 /** @hide Underlying data is corrupt */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600278 public static final int ENCRYPTION_STATE_ERROR_CORRUPT =
279 IVold.ENCRYPTION_STATE_ERROR_CORRUPT;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700280
Sudheer Shankad68bd602018-11-13 17:43:39 -0800281 /** @hide Prefix used in sandboxIds for apps with sharedUserIds */
282 public static final String SHARED_SANDBOX_PREFIX = "shared-";
283
Sudheer Shanka2250d562016-11-07 15:41:02 -0800284 private static volatile IStorageManager sStorageManager = null;
Felipe Leme179923a2016-07-19 09:33:31 -0700285
Jeff Sharkey48877892015-03-18 11:27:19 -0700286 private final Context mContext;
Jeff Sharkeybe722152013-02-15 16:56:38 -0800287 private final ContentResolver mResolver;
288
Sudheer Shanka2250d562016-11-07 15:41:02 -0800289 private final IStorageManager mStorageManager;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700290 private final Looper mLooper;
291 private final AtomicInteger mNextNonce = new AtomicInteger(0);
San Mehatb1043402010-02-05 08:26:50 -0800292
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700293 private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>();
San Mehatb1043402010-02-05 08:26:50 -0800294
Sudheer Shanka2250d562016-11-07 15:41:02 -0800295 private static class StorageEventListenerDelegate extends IStorageEventListener.Stub implements
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700296 Handler.Callback {
297 private static final int MSG_STORAGE_STATE_CHANGED = 1;
298 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700299 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
300 private static final int MSG_VOLUME_FORGOTTEN = 4;
301 private static final int MSG_DISK_SCANNED = 5;
Makoto Onuki9dc575d2015-06-12 16:10:25 -0700302 private static final int MSG_DISK_DESTROYED = 6;
San Mehatb1043402010-02-05 08:26:50 -0800303
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700304 final StorageEventListener mCallback;
305 final Handler mHandler;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700306
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700307 public StorageEventListenerDelegate(StorageEventListener callback, Looper looper) {
308 mCallback = callback;
309 mHandler = new Handler(looper, this);
San Mehatb1043402010-02-05 08:26:50 -0800310 }
311
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700312 @Override
313 public boolean handleMessage(Message msg) {
314 final SomeArgs args = (SomeArgs) msg.obj;
315 switch (msg.what) {
316 case MSG_STORAGE_STATE_CHANGED:
317 mCallback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
318 (String) args.arg3);
319 args.recycle();
320 return true;
321 case MSG_VOLUME_STATE_CHANGED:
322 mCallback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
323 args.recycle();
324 return true;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700325 case MSG_VOLUME_RECORD_CHANGED:
326 mCallback.onVolumeRecordChanged((VolumeRecord) args.arg1);
327 args.recycle();
328 return true;
329 case MSG_VOLUME_FORGOTTEN:
330 mCallback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700331 args.recycle();
332 return true;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700333 case MSG_DISK_SCANNED:
334 mCallback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700335 args.recycle();
336 return true;
Makoto Onuki9dc575d2015-06-12 16:10:25 -0700337 case MSG_DISK_DESTROYED:
338 mCallback.onDiskDestroyed((DiskInfo) args.arg1);
339 args.recycle();
340 return true;
San Mehatb1043402010-02-05 08:26:50 -0800341 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700342 args.recycle();
343 return false;
344 }
345
346 @Override
347 public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException {
348 // Ignored
349 }
350
351 @Override
352 public void onStorageStateChanged(String path, String oldState, String newState) {
353 final SomeArgs args = SomeArgs.obtain();
354 args.arg1 = path;
355 args.arg2 = oldState;
356 args.arg3 = newState;
357 mHandler.obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
358 }
359
360 @Override
361 public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
362 final SomeArgs args = SomeArgs.obtain();
363 args.arg1 = vol;
364 args.argi2 = oldState;
365 args.argi3 = newState;
366 mHandler.obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
San Mehatb1043402010-02-05 08:26:50 -0800367 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700368
369 @Override
Jeff Sharkey50a05452015-04-29 11:24:52 -0700370 public void onVolumeRecordChanged(VolumeRecord rec) {
371 final SomeArgs args = SomeArgs.obtain();
372 args.arg1 = rec;
373 mHandler.obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
374 }
375
376 @Override
377 public void onVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700378 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700379 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700380 mHandler.obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700381 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700382
383 @Override
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700384 public void onDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700385 final SomeArgs args = SomeArgs.obtain();
386 args.arg1 = disk;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700387 args.argi2 = volumeCount;
388 mHandler.obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700389 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -0700390
391 @Override
392 public void onDiskDestroyed(DiskInfo disk) throws RemoteException {
393 final SomeArgs args = SomeArgs.obtain();
394 args.arg1 = disk;
395 mHandler.obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
396 }
San Mehatb1043402010-02-05 08:26:50 -0800397 }
398
399 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700400 * Binder listener for OBB action results.
401 */
Kenny Root05105f72010-09-22 17:29:43 -0700402 private final ObbActionListener mObbActionListener = new ObbActionListener();
403
404 private class ObbActionListener extends IObbActionListener.Stub {
Gilles Debunne37051cd2011-05-25 16:27:13 -0700405 @SuppressWarnings("hiding")
Kenny Rootaf9d6672010-10-08 09:21:39 -0700406 private SparseArray<ObbListenerDelegate> mListeners = new SparseArray<ObbListenerDelegate>();
Kenny Root05105f72010-09-22 17:29:43 -0700407
Kenny Roota02b8b02010-08-05 16:14:17 -0700408 @Override
Gilles Debunne37051cd2011-05-25 16:27:13 -0700409 public void onObbResult(String filename, int nonce, int status) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700410 final ObbListenerDelegate delegate;
Kenny Root05105f72010-09-22 17:29:43 -0700411 synchronized (mListeners) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700412 delegate = mListeners.get(nonce);
413 if (delegate != null) {
414 mListeners.remove(nonce);
Kenny Root05105f72010-09-22 17:29:43 -0700415 }
416 }
Kenny Rootaf9d6672010-10-08 09:21:39 -0700417
418 if (delegate != null) {
419 delegate.sendObbStateChanged(filename, status);
420 }
Kenny Root05105f72010-09-22 17:29:43 -0700421 }
422
Kenny Rootaf9d6672010-10-08 09:21:39 -0700423 public int addListener(OnObbStateChangeListener listener) {
424 final ObbListenerDelegate delegate = new ObbListenerDelegate(listener);
Kenny Root05105f72010-09-22 17:29:43 -0700425
426 synchronized (mListeners) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700427 mListeners.put(delegate.nonce, delegate);
Kenny Root05105f72010-09-22 17:29:43 -0700428 }
Kenny Rootaf9d6672010-10-08 09:21:39 -0700429
430 return delegate.nonce;
Kenny Root05105f72010-09-22 17:29:43 -0700431 }
432 }
433
Kenny Rootaf9d6672010-10-08 09:21:39 -0700434 private int getNextNonce() {
435 return mNextNonce.getAndIncrement();
436 }
437
Kenny Root05105f72010-09-22 17:29:43 -0700438 /**
439 * Private class containing sender and receiver code for StorageEvents.
440 */
441 private class ObbListenerDelegate {
442 private final WeakReference<OnObbStateChangeListener> mObbEventListenerRef;
443 private final Handler mHandler;
444
Kenny Rootaf9d6672010-10-08 09:21:39 -0700445 private final int nonce;
446
Kenny Root05105f72010-09-22 17:29:43 -0700447 ObbListenerDelegate(OnObbStateChangeListener listener) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700448 nonce = getNextNonce();
Kenny Root05105f72010-09-22 17:29:43 -0700449 mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700450 mHandler = new Handler(mLooper) {
Kenny Root05105f72010-09-22 17:29:43 -0700451 @Override
452 public void handleMessage(Message msg) {
Gilles Debunne37051cd2011-05-25 16:27:13 -0700453 final OnObbStateChangeListener changeListener = getListener();
454 if (changeListener == null) {
Kenny Root05105f72010-09-22 17:29:43 -0700455 return;
456 }
457
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700458 changeListener.onObbStateChange((String) msg.obj, msg.arg1);
Kenny Root05105f72010-09-22 17:29:43 -0700459 }
460 };
461 }
462
463 OnObbStateChangeListener getListener() {
464 if (mObbEventListenerRef == null) {
465 return null;
466 }
467 return mObbEventListenerRef.get();
468 }
469
Kenny Rootaf9d6672010-10-08 09:21:39 -0700470 void sendObbStateChanged(String path, int state) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700471 mHandler.obtainMessage(0, state, 0, path).sendToTarget();
San Mehatb1043402010-02-05 08:26:50 -0800472 }
473 }
474
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700475 /** {@hide} */
Jeff Sharkey50a05452015-04-29 11:24:52 -0700476 @Deprecated
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100477 @UnsupportedAppUsage
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700478 public static StorageManager from(Context context) {
Jeff Sharkey50a05452015-04-29 11:24:52 -0700479 return context.getSystemService(StorageManager.class);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700480 }
481
San Mehatb1043402010-02-05 08:26:50 -0800482 /**
483 * Constructs a StorageManager object through which an application can
484 * can communicate with the systems mount service.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900485 *
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600486 * @param looper The {@link android.os.Looper} which events will be received on.
San Mehatb1043402010-02-05 08:26:50 -0800487 *
488 * <p>Applications can get instance of this class by calling
489 * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
490 * of {@link android.content.Context#STORAGE_SERVICE}.
491 *
492 * @hide
493 */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100494 @UnsupportedAppUsage
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600495 public StorageManager(Context context, Looper looper) throws ServiceNotFoundException {
Jeff Sharkey48877892015-03-18 11:27:19 -0700496 mContext = context;
497 mResolver = context.getContentResolver();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700498 mLooper = looper;
Sudheer Shanka2250d562016-11-07 15:41:02 -0800499 mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getServiceOrThrow("mount"));
San Mehatb1043402010-02-05 08:26:50 -0800500 }
501
San Mehatb1043402010-02-05 08:26:50 -0800502 /**
503 * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}.
504 *
505 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
506 *
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800507 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800508 */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100509 @UnsupportedAppUsage
San Mehatb1043402010-02-05 08:26:50 -0800510 public void registerListener(StorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700511 synchronized (mDelegates) {
512 final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(listener,
513 mLooper);
514 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800515 mStorageManager.registerListener(delegate);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700516 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700517 throw e.rethrowFromSystemServer();
Chuanxia Dong6614bb62012-05-29 12:28:24 +0800518 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700519 mDelegates.add(delegate);
San Mehatb1043402010-02-05 08:26:50 -0800520 }
521 }
522
523 /**
524 * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}.
525 *
526 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
527 *
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800528 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800529 */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100530 @UnsupportedAppUsage
San Mehatb1043402010-02-05 08:26:50 -0800531 public void unregisterListener(StorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700532 synchronized (mDelegates) {
533 for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) {
534 final StorageEventListenerDelegate delegate = i.next();
535 if (delegate.mCallback == listener) {
536 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800537 mStorageManager.unregisterListener(delegate);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700538 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700539 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700540 }
541 i.remove();
542 }
543 }
San Mehatb1043402010-02-05 08:26:50 -0800544 }
San Mehatb1043402010-02-05 08:26:50 -0800545 }
546
547 /**
548 * Enables USB Mass Storage (UMS) on the device.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800549 *
550 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800551 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700552 @Deprecated
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100553 @UnsupportedAppUsage
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800554 public void enableUsbMassStorage() {
San Mehatb1043402010-02-05 08:26:50 -0800555 }
556
557 /**
558 * Disables USB Mass Storage (UMS) on the device.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800559 *
560 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800561 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700562 @Deprecated
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100563 @UnsupportedAppUsage
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800564 public void disableUsbMassStorage() {
San Mehatb1043402010-02-05 08:26:50 -0800565 }
566
567 /**
568 * Query if a USB Mass Storage (UMS) host is connected.
569 * @return true if UMS host is connected.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800570 *
571 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800572 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700573 @Deprecated
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100574 @UnsupportedAppUsage
San Mehatb1043402010-02-05 08:26:50 -0800575 public boolean isUsbMassStorageConnected() {
San Mehatb1043402010-02-05 08:26:50 -0800576 return false;
577 }
578
579 /**
580 * Query if a USB Mass Storage (UMS) is enabled on the device.
581 * @return true if UMS host is enabled.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800582 *
583 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800584 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700585 @Deprecated
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100586 @UnsupportedAppUsage
San Mehatb1043402010-02-05 08:26:50 -0800587 public boolean isUsbMassStorageEnabled() {
San Mehatb1043402010-02-05 08:26:50 -0800588 return false;
589 }
Kenny Root02c87302010-07-01 08:10:18 -0700590
591 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700592 * Mount an Opaque Binary Blob (OBB) file. If a <code>key</code> is
593 * specified, it is supplied to the mounting process to be used in any
594 * encryption used in the OBB.
595 * <p>
Kenny Root05105f72010-09-22 17:29:43 -0700596 * The OBB will remain mounted for as long as the StorageManager reference
597 * is held by the application. As soon as this reference is lost, the OBBs
Kenny Rootaf9d6672010-10-08 09:21:39 -0700598 * in use will be unmounted. The {@link OnObbStateChangeListener} registered
599 * with this call will receive the success or failure of this operation.
Kenny Root05105f72010-09-22 17:29:43 -0700600 * <p>
Kenny Roota02b8b02010-08-05 16:14:17 -0700601 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
602 * file matches a package ID that is owned by the calling program's UID.
Kenny Root05105f72010-09-22 17:29:43 -0700603 * That is, shared UID applications can attempt to mount any other
Kenny Roota02b8b02010-08-05 16:14:17 -0700604 * application's OBB that shares its UID.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900605 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700606 * @param rawPath the path to the OBB file
Kenny Root05105f72010-09-22 17:29:43 -0700607 * @param key secret used to encrypt the OBB; may be <code>null</code> if no
608 * encryption was used on the OBB.
Kenny Rootaf9d6672010-10-08 09:21:39 -0700609 * @param listener will receive the success or failure of the operation
Kenny Roota02b8b02010-08-05 16:14:17 -0700610 * @return whether the mount call was successfully queued or not
Kenny Root02c87302010-07-01 08:10:18 -0700611 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700612 public boolean mountObb(String rawPath, String key, OnObbStateChangeListener listener) {
613 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
614 Preconditions.checkNotNull(listener, "listener cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700615
Kenny Root02c87302010-07-01 08:10:18 -0700616 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700617 final String canonicalPath = new File(rawPath).getCanonicalPath();
Kenny Rootaf9d6672010-10-08 09:21:39 -0700618 final int nonce = mObbActionListener.addListener(listener);
Sudheer Shanka25469aa2018-08-27 15:50:23 -0700619 mStorageManager.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce,
620 getObbInfo(canonicalPath));
Kenny Roota02b8b02010-08-05 16:14:17 -0700621 return true;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700622 } catch (IOException e) {
623 throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e);
Kenny Root02c87302010-07-01 08:10:18 -0700624 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700625 throw e.rethrowFromSystemServer();
Kenny Root02c87302010-07-01 08:10:18 -0700626 }
Kenny Root02c87302010-07-01 08:10:18 -0700627 }
628
Sudheer Shanka25469aa2018-08-27 15:50:23 -0700629 private ObbInfo getObbInfo(String canonicalPath) {
630 try {
631 final ObbInfo obbInfo = ObbScanner.getObbInfo(canonicalPath);
632 return obbInfo;
633 } catch (IOException e) {
634 throw new IllegalArgumentException("Couldn't get OBB info for " + canonicalPath, e);
635 }
636 }
637
Kenny Root02c87302010-07-01 08:10:18 -0700638 /**
Kenny Root05105f72010-09-22 17:29:43 -0700639 * Unmount an Opaque Binary Blob (OBB) file asynchronously. If the
640 * <code>force</code> flag is true, it will kill any application needed to
641 * unmount the given OBB (even the calling application).
642 * <p>
Kenny Rootaf9d6672010-10-08 09:21:39 -0700643 * The {@link OnObbStateChangeListener} registered with this call will
644 * receive the success or failure of this operation.
Kenny Roota02b8b02010-08-05 16:14:17 -0700645 * <p>
646 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
647 * file matches a package ID that is owned by the calling program's UID.
648 * That is, shared UID applications can obtain access to any other
649 * application's OBB that shares its UID.
Kenny Root02ca31f2010-08-12 07:36:02 -0700650 * <p>
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900651 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700652 * @param rawPath path to the OBB file
Kenny Roota02b8b02010-08-05 16:14:17 -0700653 * @param force whether to kill any programs using this in order to unmount
654 * it
Kenny Rootaf9d6672010-10-08 09:21:39 -0700655 * @param listener will receive the success or failure of the operation
Kenny Roota02b8b02010-08-05 16:14:17 -0700656 * @return whether the unmount call was successfully queued or not
Kenny Root02c87302010-07-01 08:10:18 -0700657 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700658 public boolean unmountObb(String rawPath, boolean force, OnObbStateChangeListener listener) {
659 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
660 Preconditions.checkNotNull(listener, "listener cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700661
Kenny Root02c87302010-07-01 08:10:18 -0700662 try {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700663 final int nonce = mObbActionListener.addListener(listener);
Sudheer Shanka2250d562016-11-07 15:41:02 -0800664 mStorageManager.unmountObb(rawPath, force, mObbActionListener, nonce);
Kenny Roota02b8b02010-08-05 16:14:17 -0700665 return true;
Kenny Root02c87302010-07-01 08:10:18 -0700666 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700667 throw e.rethrowFromSystemServer();
Kenny Root02c87302010-07-01 08:10:18 -0700668 }
Kenny Root02c87302010-07-01 08:10:18 -0700669 }
670
Kenny Roota02b8b02010-08-05 16:14:17 -0700671 /**
672 * Check whether an Opaque Binary Blob (OBB) is mounted or not.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900673 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700674 * @param rawPath path to OBB image
Kenny Roota02b8b02010-08-05 16:14:17 -0700675 * @return true if OBB is mounted; false if not mounted or on error
676 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700677 public boolean isObbMounted(String rawPath) {
678 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700679
Kenny Root02c87302010-07-01 08:10:18 -0700680 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800681 return mStorageManager.isObbMounted(rawPath);
Kenny Root02c87302010-07-01 08:10:18 -0700682 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700683 throw e.rethrowFromSystemServer();
Kenny Root02c87302010-07-01 08:10:18 -0700684 }
Kenny Root02c87302010-07-01 08:10:18 -0700685 }
686
687 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700688 * Check the mounted path of an Opaque Binary Blob (OBB) file. This will
689 * give you the path to where you can obtain access to the internals of the
690 * OBB.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900691 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700692 * @param rawPath path to OBB image
Kenny Roota02b8b02010-08-05 16:14:17 -0700693 * @return absolute path to mounted OBB image data or <code>null</code> if
694 * not mounted or exception encountered trying to read status
Kenny Root02c87302010-07-01 08:10:18 -0700695 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700696 public String getMountedObbPath(String rawPath) {
697 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700698
Kenny Root02c87302010-07-01 08:10:18 -0700699 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800700 return mStorageManager.getMountedObbPath(rawPath);
Kenny Root02c87302010-07-01 08:10:18 -0700701 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700702 throw e.rethrowFromSystemServer();
Kenny Root02c87302010-07-01 08:10:18 -0700703 }
Kenny Root02c87302010-07-01 08:10:18 -0700704 }
Mike Lockwoodd967f462011-03-24 08:12:30 -0700705
Jeff Sharkey48877892015-03-18 11:27:19 -0700706 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100707 @UnsupportedAppUsage
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700708 public @NonNull List<DiskInfo> getDisks() {
709 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800710 return Arrays.asList(mStorageManager.getDisks());
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700711 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700712 throw e.rethrowFromSystemServer();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700713 }
714 }
715
716 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100717 @UnsupportedAppUsage
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700718 public @Nullable DiskInfo findDiskById(String id) {
719 Preconditions.checkNotNull(id);
720 // TODO; go directly to service to make this faster
721 for (DiskInfo disk : getDisks()) {
722 if (Objects.equals(disk.id, id)) {
723 return disk;
724 }
725 }
726 return null;
727 }
728
729 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100730 @UnsupportedAppUsage
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700731 public @Nullable VolumeInfo findVolumeById(String id) {
732 Preconditions.checkNotNull(id);
733 // TODO; go directly to service to make this faster
734 for (VolumeInfo vol : getVolumes()) {
735 if (Objects.equals(vol.id, id)) {
736 return vol;
737 }
738 }
739 return null;
740 }
741
742 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100743 @UnsupportedAppUsage
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700744 public @Nullable VolumeInfo findVolumeByUuid(String fsUuid) {
745 Preconditions.checkNotNull(fsUuid);
746 // TODO; go directly to service to make this faster
747 for (VolumeInfo vol : getVolumes()) {
748 if (Objects.equals(vol.fsUuid, fsUuid)) {
749 return vol;
750 }
751 }
752 return null;
753 }
754
755 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700756 public @Nullable VolumeRecord findRecordByUuid(String fsUuid) {
757 Preconditions.checkNotNull(fsUuid);
758 // TODO; go directly to service to make this faster
759 for (VolumeRecord rec : getVolumeRecords()) {
760 if (Objects.equals(rec.fsUuid, fsUuid)) {
761 return rec;
762 }
763 }
764 return null;
765 }
766
767 /** {@hide} */
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700768 public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700769 if (emulatedVol != null) {
770 return findVolumeById(emulatedVol.getId().replace("emulated", "private"));
771 } else {
772 return null;
773 }
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700774 }
775
776 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100777 @UnsupportedAppUsage
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700778 public @Nullable VolumeInfo findEmulatedForPrivate(VolumeInfo privateVol) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700779 if (privateVol != null) {
780 return findVolumeById(privateVol.getId().replace("private", "emulated"));
781 } else {
782 return null;
783 }
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700784 }
785
786 /** {@hide} */
Jeff Sharkey50a05452015-04-29 11:24:52 -0700787 public @Nullable VolumeInfo findVolumeByQualifiedUuid(String volumeUuid) {
788 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
789 return findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL);
790 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
791 return getPrimaryPhysicalVolume();
792 } else {
793 return findVolumeByUuid(volumeUuid);
794 }
795 }
796
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600797 /**
798 * Return a UUID identifying the storage volume that hosts the given
799 * filesystem path.
800 * <p>
801 * If this path is hosted by the default internal storage of the device at
802 * {@link Environment#getDataDirectory()}, the returned value will be
803 * {@link #UUID_DEFAULT}.
804 *
Jeff Sharkey4233f032017-07-15 12:58:38 -0600805 * @throws IOException when the storage device hosting the given path isn't
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600806 * present, or when it doesn't have a valid UUID.
807 */
808 public @NonNull UUID getUuidForPath(@NonNull File path) throws IOException {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700809 Preconditions.checkNotNull(path);
Jeff Sharkey00347882017-04-17 16:44:12 -0600810 final String pathString = path.getCanonicalPath();
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700811 if (FileUtils.contains(Environment.getDataDirectory().getAbsolutePath(), pathString)) {
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600812 return UUID_DEFAULT;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700813 }
814 try {
815 for (VolumeInfo vol : mStorageManager.getVolumes(0)) {
Jeff Sharkey18f32502018-03-29 14:29:27 -0600816 if (vol.path != null && FileUtils.contains(vol.path, pathString)
Risan05c41e62018-10-29 08:57:43 +0900817 && vol.type != VolumeInfo.TYPE_PUBLIC && vol.type != VolumeInfo.TYPE_STUB) {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700818 // TODO: verify that emulated adopted devices have UUID of
819 // underlying volume
Jeff Sharkey18f32502018-03-29 14:29:27 -0600820 try {
821 return convert(vol.fsUuid);
822 } catch (IllegalArgumentException e) {
823 continue;
824 }
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700825 }
826 }
827 } catch (RemoteException e) {
828 throw e.rethrowFromSystemServer();
829 }
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600830 throw new FileNotFoundException("Failed to find a storage device for " + path);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700831 }
832
833 /** {@hide} */
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600834 public @NonNull File findPathForUuid(String volumeUuid) throws FileNotFoundException {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700835 final VolumeInfo vol = findVolumeByQualifiedUuid(volumeUuid);
836 if (vol != null) {
837 return vol.getPath();
838 }
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600839 throw new FileNotFoundException("Failed to find a storage device for " + volumeUuid);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700840 }
841
Jeff Sharkey4233f032017-07-15 12:58:38 -0600842 /**
843 * Test if the given file descriptor supports allocation of disk space using
844 * {@link #allocateBytes(FileDescriptor, long)}.
845 */
846 public boolean isAllocationSupported(@NonNull FileDescriptor fd) {
847 try {
848 getUuidForPath(ParcelFileDescriptor.getFile(fd));
849 return true;
850 } catch (IOException e) {
851 return false;
852 }
853 }
854
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700855 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100856 @UnsupportedAppUsage
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700857 public @NonNull List<VolumeInfo> getVolumes() {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700858 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800859 return Arrays.asList(mStorageManager.getVolumes(0));
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700860 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700861 throw e.rethrowFromSystemServer();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700862 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700863 }
864
865 /** {@hide} */
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700866 public @NonNull List<VolumeInfo> getWritablePrivateVolumes() {
867 try {
868 final ArrayList<VolumeInfo> res = new ArrayList<>();
Sudheer Shanka2250d562016-11-07 15:41:02 -0800869 for (VolumeInfo vol : mStorageManager.getVolumes(0)) {
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700870 if (vol.getType() == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) {
871 res.add(vol);
872 }
873 }
874 return res;
875 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700876 throw e.rethrowFromSystemServer();
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700877 }
878 }
879
880 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700881 public @NonNull List<VolumeRecord> getVolumeRecords() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700882 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800883 return Arrays.asList(mStorageManager.getVolumeRecords(0));
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700884 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700885 throw e.rethrowFromSystemServer();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700886 }
887 }
888
889 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100890 @UnsupportedAppUsage
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700891 public @Nullable String getBestVolumeDescription(VolumeInfo vol) {
Jeff Sharkey50a05452015-04-29 11:24:52 -0700892 if (vol == null) return null;
893
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700894 // Nickname always takes precedence when defined
895 if (!TextUtils.isEmpty(vol.fsUuid)) {
896 final VolumeRecord rec = findRecordByUuid(vol.fsUuid);
Jeff Sharkeyc8406812015-05-04 12:04:09 -0700897 if (rec != null && !TextUtils.isEmpty(rec.nickname)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700898 return rec.nickname;
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700899 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700900 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700901
902 if (!TextUtils.isEmpty(vol.getDescription())) {
903 return vol.getDescription();
904 }
905
906 if (vol.disk != null) {
907 return vol.disk.getDescription();
908 }
909
910 return null;
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700911 }
912
913 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100914 @UnsupportedAppUsage
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700915 public @Nullable VolumeInfo getPrimaryPhysicalVolume() {
916 final List<VolumeInfo> vols = getVolumes();
917 for (VolumeInfo vol : vols) {
918 if (vol.isPrimaryPhysical()) {
919 return vol;
920 }
921 }
922 return null;
923 }
924
925 /** {@hide} */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700926 public void mount(String volId) {
927 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800928 mStorageManager.mount(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700929 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700930 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700931 }
932 }
933
934 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100935 @UnsupportedAppUsage
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700936 public void unmount(String volId) {
937 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800938 mStorageManager.unmount(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700939 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700940 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700941 }
942 }
943
944 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100945 @UnsupportedAppUsage
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700946 public void format(String volId) {
947 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800948 mStorageManager.format(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700949 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700950 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700951 }
952 }
953
954 /** {@hide} */
Jeff Sharkey7e19f532017-11-06 13:54:11 -0700955 @Deprecated
Jeff Sharkey9756d752015-05-14 21:07:42 -0700956 public long benchmark(String volId) {
Jeff Sharkey7e19f532017-11-06 13:54:11 -0700957 final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
958 benchmark(volId, new IVoldTaskListener.Stub() {
959 @Override
960 public void onStatus(int status, PersistableBundle extras) {
961 // Ignored
962 }
963
964 @Override
965 public void onFinished(int status, PersistableBundle extras) {
966 result.complete(extras);
967 }
968 });
Jeff Sharkey9756d752015-05-14 21:07:42 -0700969 try {
Jeff Sharkey7e19f532017-11-06 13:54:11 -0700970 // Convert ms to ns
971 return result.get(3, TimeUnit.MINUTES).getLong("run", Long.MAX_VALUE) * 1000000;
972 } catch (Exception e) {
973 return Long.MAX_VALUE;
974 }
975 }
976
977 /** {@hide} */
978 public void benchmark(String volId, IVoldTaskListener listener) {
979 try {
980 mStorageManager.benchmark(volId, listener);
Jeff Sharkey9756d752015-05-14 21:07:42 -0700981 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700982 throw e.rethrowFromSystemServer();
Jeff Sharkey9756d752015-05-14 21:07:42 -0700983 }
984 }
985
986 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100987 @UnsupportedAppUsage
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700988 public void partitionPublic(String diskId) {
989 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800990 mStorageManager.partitionPublic(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700991 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700992 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700993 }
994 }
995
996 /** {@hide} */
997 public void partitionPrivate(String diskId) {
998 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800999 mStorageManager.partitionPrivate(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001000 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001001 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001002 }
1003 }
1004
1005 /** {@hide} */
1006 public void partitionMixed(String diskId, int ratio) {
1007 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001008 mStorageManager.partitionMixed(diskId, ratio);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001009 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001010 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001011 }
1012 }
1013
1014 /** {@hide} */
Jeff Sharkeyb42d6942015-04-28 22:25:26 -07001015 public void wipeAdoptableDisks() {
1016 // We only wipe devices in "adoptable" locations, which are in a
1017 // long-term stable slot/location on the device, where apps have a
1018 // reasonable chance of storing sensitive data. (Apps need to go through
1019 // SAF to write to transient volumes.)
1020 final List<DiskInfo> disks = getDisks();
1021 for (DiskInfo disk : disks) {
1022 final String diskId = disk.getId();
1023 if (disk.isAdoptable()) {
1024 Slog.d(TAG, "Found adoptable " + diskId + "; wiping");
1025 try {
1026 // TODO: switch to explicit wipe command when we have it,
1027 // for now rely on the fact that vfat format does a wipe
Sudheer Shanka2250d562016-11-07 15:41:02 -08001028 mStorageManager.partitionPublic(diskId);
Jeff Sharkeyb42d6942015-04-28 22:25:26 -07001029 } catch (Exception e) {
1030 Slog.w(TAG, "Failed to wipe " + diskId + ", but soldiering onward", e);
1031 }
1032 } else {
1033 Slog.d(TAG, "Ignorning non-adoptable disk " + disk.getId());
1034 }
1035 }
1036 }
1037
1038 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001039 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001040 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001041 mStorageManager.setVolumeNickname(fsUuid, nickname);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001042 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001043 throw e.rethrowFromSystemServer();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001044 }
1045 }
1046
1047 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001048 public void setVolumeInited(String fsUuid, boolean inited) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001049 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001050 mStorageManager.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0,
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001051 VolumeRecord.USER_FLAG_INITED);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001052 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001053 throw e.rethrowFromSystemServer();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001054 }
1055 }
1056
1057 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001058 public void setVolumeSnoozed(String fsUuid, boolean snoozed) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001059 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001060 mStorageManager.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0,
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001061 VolumeRecord.USER_FLAG_SNOOZED);
1062 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001063 throw e.rethrowFromSystemServer();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001064 }
1065 }
1066
1067 /** {@hide} */
1068 public void forgetVolume(String fsUuid) {
1069 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001070 mStorageManager.forgetVolume(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001071 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001072 throw e.rethrowFromSystemServer();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001073 }
1074 }
1075
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001076 /**
1077 * This is not the API you're looking for.
1078 *
1079 * @see PackageManager#getPrimaryStorageCurrentVolume()
1080 * @hide
1081 */
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001082 public String getPrimaryStorageUuid() {
1083 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001084 return mStorageManager.getPrimaryStorageUuid();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001085 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001086 throw e.rethrowFromSystemServer();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001087 }
1088 }
1089
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001090 /**
1091 * This is not the API you're looking for.
1092 *
1093 * @see PackageManager#movePrimaryStorage(VolumeInfo)
1094 * @hide
1095 */
1096 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001097 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001098 mStorageManager.setPrimaryStorageUuid(volumeUuid, callback);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001099 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001100 throw e.rethrowFromSystemServer();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001101 }
1102 }
1103
Felipe Lemec250e452016-04-11 18:44:33 -07001104 /**
Jeff Sharkeyf8fa9402019-02-18 13:23:51 -07001105 * Return the {@link StorageVolume} that contains the given file, or
1106 * {@code null} if none.
Felipe Lemec250e452016-04-11 18:44:33 -07001107 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001108 public @Nullable StorageVolume getStorageVolume(File file) {
1109 return getStorageVolume(getVolumeList(), file);
1110 }
1111
Jeff Sharkeyf8fa9402019-02-18 13:23:51 -07001112 /**
1113 * Return the {@link StorageVolume} that contains the given
1114 * {@link MediaStore} item.
1115 */
1116 public @NonNull StorageVolume getStorageVolume(@NonNull Uri uri) {
1117 final String volumeName = MediaStore.getVolumeName(uri);
1118 switch (volumeName) {
1119 case MediaStore.VOLUME_EXTERNAL:
1120 return getPrimaryStorageVolume();
1121 default:
1122 for (StorageVolume vol : getStorageVolumes()) {
1123 if (Objects.equals(vol.getNormalizedUuid(), volumeName)) {
1124 return vol;
1125 }
1126 }
1127 }
1128 throw new IllegalStateException("Unknown volume for " + uri);
1129 }
1130
Jeff Sharkey48877892015-03-18 11:27:19 -07001131 /** {@hide} */
1132 public static @Nullable StorageVolume getStorageVolume(File file, int userId) {
Jeff Sharkey46349872015-07-28 10:49:47 -07001133 return getStorageVolume(getVolumeList(userId, 0), file);
Jeff Sharkey48877892015-03-18 11:27:19 -07001134 }
1135
1136 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +01001137 @UnsupportedAppUsage
Jeff Sharkey48877892015-03-18 11:27:19 -07001138 private static @Nullable StorageVolume getStorageVolume(StorageVolume[] volumes, File file) {
Felipe Lemec250e452016-04-11 18:44:33 -07001139 if (file == null) {
1140 return null;
1141 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001142 try {
Jeff Sharkey983294592015-07-13 10:25:31 -07001143 file = file.getCanonicalFile();
Jeff Sharkey48877892015-03-18 11:27:19 -07001144 } catch (IOException ignored) {
Felipe Lemec250e452016-04-11 18:44:33 -07001145 Slog.d(TAG, "Could not get canonical path for " + file);
Jeff Sharkey983294592015-07-13 10:25:31 -07001146 return null;
Jeff Sharkey48877892015-03-18 11:27:19 -07001147 }
1148 for (StorageVolume volume : volumes) {
Jeff Sharkey983294592015-07-13 10:25:31 -07001149 File volumeFile = volume.getPathFile();
1150 try {
1151 volumeFile = volumeFile.getCanonicalFile();
1152 } catch (IOException ignored) {
1153 continue;
Jeff Sharkey48877892015-03-18 11:27:19 -07001154 }
Jeff Sharkey983294592015-07-13 10:25:31 -07001155 if (FileUtils.contains(volumeFile, file)) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001156 return volume;
1157 }
1158 }
1159 return null;
1160 }
1161
Mike Lockwoodd967f462011-03-24 08:12:30 -07001162 /**
1163 * Gets the state of a volume via its mountpoint.
1164 * @hide
1165 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001166 @Deprecated
Mathew Inwood98e9ad12018-08-30 13:11:50 +01001167 @UnsupportedAppUsage
Jeff Sharkey48877892015-03-18 11:27:19 -07001168 public @NonNull String getVolumeState(String mountPoint) {
1169 final StorageVolume vol = getStorageVolume(new File(mountPoint));
1170 if (vol != null) {
1171 return vol.getState();
1172 } else {
1173 return Environment.MEDIA_UNKNOWN;
Mike Lockwoodd967f462011-03-24 08:12:30 -07001174 }
1175 }
1176
Felipe Leme04a5d402016-02-08 16:44:06 -08001177 /**
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001178 * Return the list of shared/external storage volumes available to the
1179 * current user. This includes both the primary shared storage device and
1180 * any attached external volumes including SD cards and USB drives.
Felipe Leme04a5d402016-02-08 16:44:06 -08001181 *
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001182 * @see Environment#getExternalStorageDirectory()
1183 * @see StorageVolume#createAccessIntent(String)
Felipe Leme04a5d402016-02-08 16:44:06 -08001184 */
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001185 public @NonNull List<StorageVolume> getStorageVolumes() {
1186 final ArrayList<StorageVolume> res = new ArrayList<>();
1187 Collections.addAll(res,
Jeff Sharkeyad357d12018-02-02 13:25:31 -07001188 getVolumeList(mContext.getUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE));
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001189 return res;
1190 }
1191
1192 /**
1193 * Return the primary shared/external storage volume available to the
1194 * current user. This volume is the same storage device returned by
1195 * {@link Environment#getExternalStorageDirectory()} and
1196 * {@link Context#getExternalFilesDir(String)}.
1197 */
1198 public @NonNull StorageVolume getPrimaryStorageVolume() {
Jeff Sharkeyad357d12018-02-02 13:25:31 -07001199 return getVolumeList(mContext.getUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE)[0];
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001200 }
1201
Felipe Leme18202e00b2016-05-12 12:56:28 -07001202 /** {@hide} */
Felipe Leme281389a2016-10-10 17:12:20 -07001203 public static Pair<String, Long> getPrimaryStoragePathAndSize() {
Jeff Sharkey24403ff2017-04-04 15:09:58 -06001204 return Pair.create(null,
hj.seoe82e89ef92017-12-20 09:39:47 +09001205 FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace()
1206 + Environment.getRootDirectory().getTotalSpace()));
Felipe Leme18202e00b2016-05-12 12:56:28 -07001207 }
1208
Felipe Leme281389a2016-10-10 17:12:20 -07001209 /** {@hide} */
1210 public long getPrimaryStorageSize() {
hj.seoe82e89ef92017-12-20 09:39:47 +09001211 return FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace()
1212 + Environment.getRootDirectory().getTotalSpace());
Felipe Leme18202e00b2016-05-12 12:56:28 -07001213 }
1214
Jeff Sharkeyae266462017-11-27 13:32:24 -07001215 /** {@hide} */
1216 public void mkdirs(File file) {
Jeff Sharkeydd02e332018-06-27 14:41:57 -06001217 BlockGuard.getVmPolicy().onPathAccess(file.getAbsolutePath());
Jeff Sharkeyae266462017-11-27 13:32:24 -07001218 try {
1219 mStorageManager.mkdirs(mContext.getOpPackageName(), file.getAbsolutePath());
1220 } catch (RemoteException e) {
1221 throw e.rethrowFromSystemServer();
1222 }
1223 }
1224
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001225 /** @removed */
Jeff Sharkey48877892015-03-18 11:27:19 -07001226 public @NonNull StorageVolume[] getVolumeList() {
Jeff Sharkey46349872015-07-28 10:49:47 -07001227 return getVolumeList(mContext.getUserId(), 0);
Jeff Sharkey48877892015-03-18 11:27:19 -07001228 }
1229
1230 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +01001231 @UnsupportedAppUsage
Jeff Sharkey46349872015-07-28 10:49:47 -07001232 public static @NonNull StorageVolume[] getVolumeList(int userId, int flags) {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001233 final IStorageManager storageManager = IStorageManager.Stub.asInterface(
Jeff Sharkey48877892015-03-18 11:27:19 -07001234 ServiceManager.getService("mount"));
1235 try {
Svetoslav7395cbf2015-07-15 15:58:01 -07001236 String packageName = ActivityThread.currentOpPackageName();
1237 if (packageName == null) {
1238 // Package name can be null if the activity thread is running but the app
1239 // hasn't bound yet. In this case we fall back to the first package in the
1240 // current UID. This works for runtime permissions as permission state is
1241 // per UID and permission realted app ops are updated for all UID packages.
1242 String[] packageNames = ActivityThread.getPackageManager().getPackagesForUid(
1243 android.os.Process.myUid());
1244 if (packageNames == null || packageNames.length <= 0) {
1245 return new StorageVolume[0];
1246 }
1247 packageName = packageNames[0];
1248 }
Jeff Sharkeycd654482016-01-08 17:42:11 -07001249 final int uid = ActivityThread.getPackageManager().getPackageUid(packageName,
Jeff Sharkeyc5967e92016-01-07 18:50:29 -07001250 PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
Svetoslav7395cbf2015-07-15 15:58:01 -07001251 if (uid <= 0) {
1252 return new StorageVolume[0];
1253 }
Sudheer Shanka2250d562016-11-07 15:41:02 -08001254 return storageManager.getVolumeList(uid, packageName, flags);
Jeff Sharkey48877892015-03-18 11:27:19 -07001255 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001256 throw e.rethrowFromSystemServer();
Mike Lockwoodd967f462011-03-24 08:12:30 -07001257 }
1258 }
Mike Lockwood2f6a3882011-05-09 19:08:06 -07001259
1260 /**
1261 * Returns list of paths for all mountable volumes.
1262 * @hide
1263 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001264 @Deprecated
Mathew Inwood98e9ad12018-08-30 13:11:50 +01001265 @UnsupportedAppUsage
Jeff Sharkey48877892015-03-18 11:27:19 -07001266 public @NonNull String[] getVolumePaths() {
Mike Lockwood2f6a3882011-05-09 19:08:06 -07001267 StorageVolume[] volumes = getVolumeList();
Mike Lockwood2f6a3882011-05-09 19:08:06 -07001268 int count = volumes.length;
1269 String[] paths = new String[count];
1270 for (int i = 0; i < count; i++) {
1271 paths[i] = volumes[i].getPath();
1272 }
1273 return paths;
1274 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001275
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001276 /** @removed */
Jeff Sharkey48877892015-03-18 11:27:19 -07001277 public @NonNull StorageVolume getPrimaryVolume() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001278 return getPrimaryVolume(getVolumeList());
1279 }
1280
1281 /** {@hide} */
Jeff Sharkey48877892015-03-18 11:27:19 -07001282 public static @NonNull StorageVolume getPrimaryVolume(StorageVolume[] volumes) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001283 for (StorageVolume volume : volumes) {
1284 if (volume.isPrimary()) {
1285 return volume;
1286 }
1287 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001288 throw new IllegalStateException("Missing primary storage");
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001289 }
Jeff Sharkeybe722152013-02-15 16:56:38 -08001290
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001291 private static final int DEFAULT_THRESHOLD_PERCENTAGE = 5;
Jeff Sharkey9f2dc052018-01-07 16:47:31 -07001292 private static final long DEFAULT_THRESHOLD_MAX_BYTES = DataUnit.MEBIBYTES.toBytes(500);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001293
1294 private static final int DEFAULT_CACHE_PERCENTAGE = 10;
Jeff Sharkey9f2dc052018-01-07 16:47:31 -07001295 private static final long DEFAULT_CACHE_MAX_BYTES = DataUnit.GIBIBYTES.toBytes(5);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001296
Jeff Sharkey9f2dc052018-01-07 16:47:31 -07001297 private static final long DEFAULT_FULL_THRESHOLD_BYTES = DataUnit.MEBIBYTES.toBytes(1);
Jeff Sharkeybe722152013-02-15 16:56:38 -08001298
1299 /**
Jeff Sharkey742e7902014-08-16 19:09:13 -07001300 * Return the number of available bytes until the given path is considered
1301 * running low on storage.
1302 *
1303 * @hide
1304 */
Mathew Inwood98e9ad12018-08-30 13:11:50 +01001305 @UnsupportedAppUsage
Jeff Sharkey742e7902014-08-16 19:09:13 -07001306 public long getStorageBytesUntilLow(File path) {
1307 return path.getUsableSpace() - getStorageFullBytes(path);
1308 }
1309
1310 /**
Jeff Sharkeybe722152013-02-15 16:56:38 -08001311 * Return the number of available bytes at which the given path is
1312 * considered running low on storage.
1313 *
1314 * @hide
1315 */
Mathew Inwood98e9ad12018-08-30 13:11:50 +01001316 @UnsupportedAppUsage
Jeff Sharkeybe722152013-02-15 16:56:38 -08001317 public long getStorageLowBytes(File path) {
1318 final long lowPercent = Settings.Global.getInt(mResolver,
1319 Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE);
1320 final long lowBytes = (path.getTotalSpace() * lowPercent) / 100;
1321
1322 final long maxLowBytes = Settings.Global.getLong(mResolver,
1323 Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES);
1324
1325 return Math.min(lowBytes, maxLowBytes);
1326 }
1327
1328 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001329 * Return the minimum number of bytes of storage on the device that should
1330 * be reserved for cached data.
1331 *
1332 * @hide
1333 */
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001334 public long getStorageCacheBytes(File path, @AllocateFlags int flags) {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001335 final long cachePercent = Settings.Global.getInt(mResolver,
1336 Settings.Global.SYS_STORAGE_CACHE_PERCENTAGE, DEFAULT_CACHE_PERCENTAGE);
1337 final long cacheBytes = (path.getTotalSpace() * cachePercent) / 100;
1338
1339 final long maxCacheBytes = Settings.Global.getLong(mResolver,
1340 Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES, DEFAULT_CACHE_MAX_BYTES);
1341
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001342 final long result = Math.min(cacheBytes, maxCacheBytes);
1343 if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
1344 return 0;
1345 } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED) != 0) {
1346 return 0;
1347 } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED) != 0) {
1348 return result / 2;
1349 } else {
1350 return result;
1351 }
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001352 }
1353
1354 /**
Jeff Sharkeybe722152013-02-15 16:56:38 -08001355 * Return the number of available bytes at which the given path is
1356 * considered full.
1357 *
1358 * @hide
1359 */
Mathew Inwood98e9ad12018-08-30 13:11:50 +01001360 @UnsupportedAppUsage
Jeff Sharkeybe722152013-02-15 16:56:38 -08001361 public long getStorageFullBytes(File path) {
1362 return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
1363 DEFAULT_FULL_THRESHOLD_BYTES);
1364 }
Paul Lawrencee8fdc542014-05-28 07:14:17 -07001365
Jeff Sharkey50a05452015-04-29 11:24:52 -07001366 /** {@hide} */
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01001367 public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
Paul Crowleybcf48ed2015-04-22 13:36:59 +01001368 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001369 mStorageManager.createUserKey(userId, serialNumber, ephemeral);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01001370 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001371 throw e.rethrowFromSystemServer();
Paul Crowleybcf48ed2015-04-22 13:36:59 +01001372 }
1373 }
1374
1375 /** {@hide} */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001376 public void destroyUserKey(int userId) {
Paul Crowley7ec733f2015-05-19 12:42:00 +01001377 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001378 mStorageManager.destroyUserKey(userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001379 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001380 throw e.rethrowFromSystemServer();
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001381 }
1382 }
1383
1384 /** {@hide} */
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001385 public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001386 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001387 mStorageManager.unlockUserKey(userId, serialNumber, token, secret);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001388 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001389 throw e.rethrowFromSystemServer();
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001390 }
1391 }
1392
1393 /** {@hide} */
1394 public void lockUserKey(int userId) {
1395 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001396 mStorageManager.lockUserKey(userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001397 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001398 throw e.rethrowFromSystemServer();
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001399 }
1400 }
1401
1402 /** {@hide} */
Jeff Sharkey47f71082016-02-01 17:03:54 -07001403 public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001404 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001405 mStorageManager.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001406 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001407 throw e.rethrowFromSystemServer();
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001408 }
1409 }
1410
1411 /** {@hide} */
Jeff Sharkeyfcf1e552016-04-14 20:44:58 -06001412 public void destroyUserStorage(String volumeUuid, int userId, int flags) {
1413 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001414 mStorageManager.destroyUserStorage(volumeUuid, userId, flags);
Jeff Sharkeyfcf1e552016-04-14 20:44:58 -06001415 } catch (RemoteException e) {
1416 throw e.rethrowFromSystemServer();
1417 }
1418 }
1419
1420 /** {@hide} */
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001421 public static boolean isUserKeyUnlocked(int userId) {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001422 if (sStorageManager == null) {
1423 sStorageManager = IStorageManager.Stub
Jeff Sharkey4815ed42016-05-26 09:31:04 -06001424 .asInterface(ServiceManager.getService("mount"));
1425 }
Sudheer Shanka2250d562016-11-07 15:41:02 -08001426 if (sStorageManager == null) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001427 Slog.w(TAG, "Early during boot, assuming locked");
1428 return false;
1429 }
1430 final long token = Binder.clearCallingIdentity();
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001431 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001432 return sStorageManager.isUserKeyUnlocked(userId);
Paul Crowley7ec733f2015-05-19 12:42:00 +01001433 } catch (RemoteException e) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001434 throw e.rethrowAsRuntimeException();
1435 } finally {
1436 Binder.restoreCallingIdentity(token);
Paul Crowley7ec733f2015-05-19 12:42:00 +01001437 }
1438 }
1439
Jeff Sharkeycf3f0a12016-03-17 19:57:58 -06001440 /**
Jeff Sharkeyf82c2f02016-04-12 15:19:10 -06001441 * Return if data stored at or under the given path will be encrypted while
1442 * at rest. This can help apps avoid the overhead of double-encrypting data.
Jeff Sharkeycf3f0a12016-03-17 19:57:58 -06001443 */
1444 public boolean isEncrypted(File file) {
1445 if (FileUtils.contains(Environment.getDataDirectory(), file)) {
1446 return isEncrypted();
1447 } else if (FileUtils.contains(Environment.getExpandDirectory(), file)) {
1448 return true;
1449 }
1450 // TODO: extend to support shared storage
1451 return false;
1452 }
1453
Paul Lawrence20be5d62016-02-26 13:51:17 -08001454 /** {@hide}
1455 * Is this device encryptable or already encrypted?
1456 * @return true for encryptable or encrypted
1457 * false not encrypted and not encryptable
1458 */
1459 public static boolean isEncryptable() {
John Reckaa67f682016-09-20 14:24:21 -07001460 return RoSystemProperties.CRYPTO_ENCRYPTABLE;
Paul Lawrence20be5d62016-02-26 13:51:17 -08001461 }
1462
1463 /** {@hide}
1464 * Is this device already encrypted?
1465 * @return true for encrypted. (Implies isEncryptable() == true)
1466 * false not encrypted
1467 */
1468 public static boolean isEncrypted() {
John Reckaa67f682016-09-20 14:24:21 -07001469 return RoSystemProperties.CRYPTO_ENCRYPTED;
Paul Lawrence20be5d62016-02-26 13:51:17 -08001470 }
1471
1472 /** {@hide}
1473 * Is this device file encrypted?
1474 * @return true for file encrypted. (Implies isEncrypted() == true)
1475 * false not encrypted or block encrypted
1476 */
Mathew Inwood98e9ad12018-08-30 13:11:50 +01001477 @UnsupportedAppUsage
Paul Lawrence20be5d62016-02-26 13:51:17 -08001478 public static boolean isFileEncryptedNativeOnly() {
1479 if (!isEncrypted()) {
1480 return false;
1481 }
John Reckaa67f682016-09-20 14:24:21 -07001482 return RoSystemProperties.CRYPTO_FILE_ENCRYPTED;
Paul Lawrence20be5d62016-02-26 13:51:17 -08001483 }
1484
1485 /** {@hide}
1486 * Is this device block encrypted?
1487 * @return true for block encrypted. (Implies isEncrypted() == true)
1488 * false not encrypted or file encrypted
1489 */
1490 public static boolean isBlockEncrypted() {
1491 if (!isEncrypted()) {
1492 return false;
1493 }
John Reckaa67f682016-09-20 14:24:21 -07001494 return RoSystemProperties.CRYPTO_BLOCK_ENCRYPTED;
Paul Lawrence20be5d62016-02-26 13:51:17 -08001495 }
1496
1497 /** {@hide}
1498 * Is this device block encrypted with credentials?
1499 * @return true for crediential block encrypted.
1500 * (Implies isBlockEncrypted() == true)
1501 * false not encrypted, file encrypted or default block encrypted
1502 */
1503 public static boolean isNonDefaultBlockEncrypted() {
1504 if (!isBlockEncrypted()) {
1505 return false;
1506 }
1507
1508 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001509 IStorageManager storageManager = IStorageManager.Stub.asInterface(
Paul Lawrence20be5d62016-02-26 13:51:17 -08001510 ServiceManager.getService("mount"));
Sudheer Shanka2250d562016-11-07 15:41:02 -08001511 return storageManager.getPasswordType() != CRYPT_TYPE_DEFAULT;
Paul Lawrence20be5d62016-02-26 13:51:17 -08001512 } catch (RemoteException e) {
1513 Log.e(TAG, "Error getting encryption type");
1514 return false;
1515 }
1516 }
1517
1518 /** {@hide}
1519 * Is this device in the process of being block encrypted?
1520 * @return true for encrypting.
1521 * false otherwise
1522 * Whether device isEncrypted at this point is undefined
1523 * Note that only system services and CryptKeeper will ever see this return
1524 * true - no app will ever be launched in this state.
1525 * Also note that this state will not change without a teardown of the
1526 * framework, so no service needs to check for changes during their lifespan
1527 */
1528 public static boolean isBlockEncrypting() {
Inseob Kimc1246e62018-11-08 13:13:54 +09001529 final String state = VoldProperties.encrypt_progress().orElse("");
Paul Lawrence20be5d62016-02-26 13:51:17 -08001530 return !"".equalsIgnoreCase(state);
1531 }
1532
1533 /** {@hide}
1534 * Is this device non default block encrypted and in the process of
1535 * prompting for credentials?
1536 * @return true for prompting for credentials.
1537 * (Implies isNonDefaultBlockEncrypted() == true)
1538 * false otherwise
1539 * Note that only system services and CryptKeeper will ever see this return
1540 * true - no app will ever be launched in this state.
1541 * Also note that this state will not change without a teardown of the
1542 * framework, so no service needs to check for changes during their lifespan
1543 */
1544 public static boolean inCryptKeeperBounce() {
Inseob Kimc1246e62018-11-08 13:13:54 +09001545 final String status = VoldProperties.decrypt().orElse("");
Paul Lawrence20be5d62016-02-26 13:51:17 -08001546 return "trigger_restart_min_framework".equals(status);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001547 }
1548
1549 /** {@hide} */
Paul Lawrence20be5d62016-02-26 13:51:17 -08001550 public static boolean isFileEncryptedEmulatedOnly() {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001551 return SystemProperties.getBoolean(StorageManager.PROP_EMULATE_FBE, false);
Clara Bayarri965da392015-10-28 17:53:53 +00001552 }
1553
Paul Lawrence20be5d62016-02-26 13:51:17 -08001554 /** {@hide}
1555 * Is this device running in a file encrypted mode, either native or emulated?
1556 * @return true for file encrypted, false otherwise
1557 */
1558 public static boolean isFileEncryptedNativeOrEmulated() {
1559 return isFileEncryptedNativeOnly()
1560 || isFileEncryptedEmulatedOnly();
1561 }
1562
Clara Bayarri965da392015-10-28 17:53:53 +00001563 /** {@hide} */
Jeff Sharkey8eb783b2018-01-04 16:46:48 -07001564 public static boolean hasAdoptable() {
1565 return SystemProperties.getBoolean(PROP_HAS_ADOPTABLE, false);
1566 }
1567
Jeff Sharkeyb91eaa52019-02-19 11:09:13 -07001568 /**
1569 * Return if the currently booted device has the "isolated storage" feature
1570 * flag enabled. This will eventually be fully enabled in the final
1571 * {@link android.os.Build.VERSION_CODES#Q} release.
1572 *
1573 * @hide
1574 */
Jeff Sharkeya1767a292019-01-05 12:59:04 -07001575 @SystemApi
Jeff Sharkey10ec9d82018-11-28 14:52:45 -07001576 @TestApi
1577 public static boolean hasIsolatedStorage() {
Jeff Sharkey342b4bf2018-12-18 11:12:40 -07001578 // Prefer to use snapshot for current boot when available
1579 return SystemProperties.getBoolean(PROP_ISOLATED_STORAGE_SNAPSHOT,
Jeff Sharkey06376802019-02-11 12:20:02 -07001580 SystemProperties.getBoolean(PROP_ISOLATED_STORAGE, true));
Jeff Sharkey10ec9d82018-11-28 14:52:45 -07001581 }
1582
Jeff Sharkey70eb34a2018-09-13 11:57:03 -06001583 /**
1584 * @deprecated disabled now that FUSE has been replaced by sdcardfs
1585 * @hide
1586 */
1587 @Deprecated
Jeff Sharkey50a05452015-04-29 11:24:52 -07001588 public static File maybeTranslateEmulatedPathToInternal(File path) {
Jeff Sharkey2063e4f2017-06-06 16:03:24 -06001589 // Disabled now that FUSE has been replaced by sdcardfs
Jeff Sharkey50a05452015-04-29 11:24:52 -07001590 return path;
1591 }
1592
Jeff Sharkey5790af02018-08-13 17:42:54 -06001593 /**
1594 * Translate given shared storage path from a path in an app sandbox
1595 * namespace to a path in the system namespace.
1596 *
1597 * @hide
1598 */
Sudheer Shanka87915d62018-11-06 10:57:35 -08001599 public File translateAppToSystem(File file, int pid, int uid) {
Jeff Sharkeyd2b64d72018-10-19 15:40:03 -06001600 // We can only translate absolute paths
1601 if (!file.isAbsolute()) return file;
1602
Jeff Sharkey5790af02018-08-13 17:42:54 -06001603 try {
1604 return new File(mStorageManager.translateAppToSystem(file.getAbsolutePath(),
Sudheer Shanka87915d62018-11-06 10:57:35 -08001605 pid, uid));
Jeff Sharkey5790af02018-08-13 17:42:54 -06001606 } catch (RemoteException e) {
1607 throw e.rethrowFromSystemServer();
1608 }
1609 }
1610
1611 /**
1612 * Translate given shared storage path from a path in the system namespace
1613 * to a path in an app sandbox namespace.
1614 *
1615 * @hide
1616 */
Sudheer Shanka87915d62018-11-06 10:57:35 -08001617 public File translateSystemToApp(File file, int pid, int uid) {
Jeff Sharkeyd2b64d72018-10-19 15:40:03 -06001618 // We can only translate absolute paths
1619 if (!file.isAbsolute()) return file;
1620
Jeff Sharkey5790af02018-08-13 17:42:54 -06001621 try {
1622 return new File(mStorageManager.translateSystemToApp(file.getAbsolutePath(),
Sudheer Shanka87915d62018-11-06 10:57:35 -08001623 pid, uid));
Jeff Sharkey5790af02018-08-13 17:42:54 -06001624 } catch (RemoteException e) {
1625 throw e.rethrowFromSystemServer();
1626 }
1627 }
1628
Daichi Hirono9e8d9e22015-11-13 14:37:00 +09001629 /** {@hide} */
Daichi Hirono9fb00182016-11-08 14:12:17 +09001630 @VisibleForTesting
1631 public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
Daichi Hirono812c95d2017-02-08 16:20:20 +09001632 int mode, ProxyFileDescriptorCallback callback, Handler handler, ThreadFactory factory)
Daichi Hirono9fb00182016-11-08 14:12:17 +09001633 throws IOException {
Daichi Hirono2443a092017-04-28 14:53:19 +09001634 Preconditions.checkNotNull(callback);
Daichi Hironod61817e2017-02-13 10:37:11 +09001635 MetricsLogger.count(mContext, "storage_open_proxy_file_descriptor", 1);
Daichi Hirono9fb00182016-11-08 14:12:17 +09001636 // Retry is needed because the mount point mFuseAppLoop is using may be unmounted before
1637 // invoking StorageManagerService#openProxyFileDescriptor. In this case, we need to re-mount
1638 // the bridge by calling mountProxyFileDescriptorBridge.
Daichi Hirono812c95d2017-02-08 16:20:20 +09001639 while (true) {
Daichi Hirono9fb00182016-11-08 14:12:17 +09001640 try {
1641 synchronized (mFuseAppLoopLock) {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001642 boolean newlyCreated = false;
Daichi Hirono9fb00182016-11-08 14:12:17 +09001643 if (mFuseAppLoop == null) {
1644 final AppFuseMount mount = mStorageManager.mountProxyFileDescriptorBridge();
1645 if (mount == null) {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001646 throw new IOException("Failed to mount proxy bridge");
Daichi Hirono9fb00182016-11-08 14:12:17 +09001647 }
Daichi Hirono812c95d2017-02-08 16:20:20 +09001648 mFuseAppLoop = new FuseAppLoop(mount.mountPointId, mount.fd, factory);
1649 newlyCreated = true;
Daichi Hirono9fb00182016-11-08 14:12:17 +09001650 }
Daichi Hirono812c95d2017-02-08 16:20:20 +09001651 if (handler == null) {
1652 handler = new Handler(Looper.getMainLooper());
1653 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09001654 try {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001655 final int fileId = mFuseAppLoop.registerCallback(callback, handler);
1656 final ParcelFileDescriptor pfd = mStorageManager.openProxyFileDescriptor(
1657 mFuseAppLoop.getMountPointId(), fileId, mode);
1658 if (pfd == null) {
1659 mFuseAppLoop.unregisterCallback(fileId);
1660 throw new FuseUnavailableMountException(
1661 mFuseAppLoop.getMountPointId());
Daichi Hirono9fb00182016-11-08 14:12:17 +09001662 }
Daichi Hirono812c95d2017-02-08 16:20:20 +09001663 return pfd;
1664 } catch (FuseUnavailableMountException exception) {
1665 // The bridge is being unmounted. Tried to recreate it unless the bridge was
1666 // just created.
1667 if (newlyCreated) {
1668 throw new IOException(exception);
1669 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09001670 mFuseAppLoop = null;
1671 continue;
1672 }
1673 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09001674 } catch (RemoteException e) {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001675 // Cannot recover from remote exception.
1676 throw new IOException(e);
Daichi Hirono9fb00182016-11-08 14:12:17 +09001677 }
1678 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09001679 }
1680
Daichi Hirono2443a092017-04-28 14:53:19 +09001681 /** {@hide} */
Daichi Hirono9fb00182016-11-08 14:12:17 +09001682 public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
1683 int mode, ProxyFileDescriptorCallback callback)
1684 throws IOException {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001685 return openProxyFileDescriptor(mode, callback, null, null);
Daichi Hirono9fb00182016-11-08 14:12:17 +09001686 }
1687
Daichi Hirono812c95d2017-02-08 16:20:20 +09001688 /**
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001689 * Opens a seekable {@link ParcelFileDescriptor} that proxies all low-level
1690 * I/O requests back to the given {@link ProxyFileDescriptorCallback}.
1691 * <p>
1692 * This can be useful when you want to provide quick access to a large file
1693 * that isn't backed by a real file on disk, such as a file on a network
1694 * share, cloud storage service, etc. As an example, you could respond to a
1695 * {@link ContentResolver#openFileDescriptor(android.net.Uri, String)}
1696 * request by returning a {@link ParcelFileDescriptor} created with this
1697 * method, and then stream the content on-demand as requested.
1698 * <p>
1699 * Another useful example might be where you have an encrypted file that
1700 * you're willing to decrypt on-demand, but where you want to avoid
1701 * persisting the cleartext version.
Daichi Hirono812c95d2017-02-08 16:20:20 +09001702 *
1703 * @param mode The desired access mode, must be one of
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001704 * {@link ParcelFileDescriptor#MODE_READ_ONLY},
1705 * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or
1706 * {@link ParcelFileDescriptor#MODE_READ_WRITE}
1707 * @param callback Callback to process file operation requests issued on
1708 * returned file descriptor.
Daichi Hirono812c95d2017-02-08 16:20:20 +09001709 * @param handler Handler that invokes callback methods.
1710 * @return Seekable ParcelFileDescriptor.
1711 * @throws IOException
1712 */
1713 public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
1714 int mode, ProxyFileDescriptorCallback callback, Handler handler)
1715 throws IOException {
Daichi Hirono2443a092017-04-28 14:53:19 +09001716 Preconditions.checkNotNull(handler);
Daichi Hirono812c95d2017-02-08 16:20:20 +09001717 return openProxyFileDescriptor(mode, callback, handler, null);
1718 }
1719
Daichi Hirono9fb00182016-11-08 14:12:17 +09001720 /** {@hide} */
1721 @VisibleForTesting
1722 public int getProxyFileDescriptorMountPointId() {
1723 synchronized (mFuseAppLoopLock) {
1724 return mFuseAppLoop != null ? mFuseAppLoop.getMountPointId() : -1;
1725 }
1726 }
1727
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001728 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001729 * Return quota size in bytes for all cached data belonging to the calling
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001730 * app on the given storage volume.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001731 * <p>
1732 * If your app goes above this quota, your cached files will be some of the
1733 * first to be deleted when additional disk space is needed. Conversely, if
1734 * your app stays under this quota, your cached files will be some of the
1735 * last to be deleted when additional disk space is needed.
1736 * <p>
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001737 * This quota will change over time depending on how frequently the user
Jeff Sharkey60a82cd2017-04-18 18:19:16 -06001738 * interacts with your app, and depending on how much system-wide disk space
1739 * is used.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001740 * <p class="note">
1741 * Note: if your app uses the {@code android:sharedUserId} manifest feature,
1742 * then cached data for all packages in your shared UID is tracked together
1743 * as a single unit.
1744 * </p>
1745 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001746 * @param storageUuid the UUID of the storage volume that you're interested
1747 * in. The UUID for a specific path can be obtained using
1748 * {@link #getUuidForPath(File)}.
1749 * @throws IOException when the storage device isn't present, or when it
1750 * doesn't support cache quotas.
1751 * @see #getCacheSizeBytes(UUID)
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001752 */
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001753 @WorkerThread
1754 public @BytesLong long getCacheQuotaBytes(@NonNull UUID storageUuid) throws IOException {
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001755 try {
1756 final ApplicationInfo app = mContext.getApplicationInfo();
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001757 return mStorageManager.getCacheQuotaBytes(convert(storageUuid), app.uid);
1758 } catch (ParcelableException e) {
1759 e.maybeRethrow(IOException.class);
1760 throw new RuntimeException(e);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001761 } catch (RemoteException e) {
1762 throw e.rethrowFromSystemServer();
1763 }
1764 }
1765
1766 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001767 * Return total size in bytes of all cached data belonging to the calling
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001768 * app on the given storage volume.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001769 * <p>
1770 * Cached data tracked by this method always includes
1771 * {@link Context#getCacheDir()} and {@link Context#getCodeCacheDir()}, and
1772 * it also includes {@link Context#getExternalCacheDir()} if the primary
1773 * shared/external storage is hosted on the same storage device as your
1774 * private data.
1775 * <p class="note">
1776 * Note: if your app uses the {@code android:sharedUserId} manifest feature,
1777 * then cached data for all packages in your shared UID is tracked together
1778 * as a single unit.
1779 * </p>
1780 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001781 * @param storageUuid the UUID of the storage volume that you're interested
1782 * in. The UUID for a specific path can be obtained using
1783 * {@link #getUuidForPath(File)}.
1784 * @throws IOException when the storage device isn't present, or when it
1785 * doesn't support cache quotas.
1786 * @see #getCacheQuotaBytes(UUID)
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001787 */
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001788 @WorkerThread
1789 public @BytesLong long getCacheSizeBytes(@NonNull UUID storageUuid) throws IOException {
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001790 try {
1791 final ApplicationInfo app = mContext.getApplicationInfo();
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001792 return mStorageManager.getCacheSizeBytes(convert(storageUuid), app.uid);
1793 } catch (ParcelableException e) {
1794 e.maybeRethrow(IOException.class);
1795 throw new RuntimeException(e);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001796 } catch (RemoteException e) {
1797 throw e.rethrowFromSystemServer();
1798 }
1799 }
1800
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001801 /**
1802 * Flag indicating that a disk space allocation request should operate in an
1803 * aggressive mode. This flag should only be rarely used in situations that
1804 * are critical to system health or security.
1805 * <p>
1806 * When set, the system is more aggressive about the data that it considers
1807 * for possible deletion when allocating disk space.
1808 * <p class="note">
1809 * Note: your app must hold the
1810 * {@link android.Manifest.permission#ALLOCATE_AGGRESSIVE} permission for
1811 * this flag to take effect.
1812 * </p>
1813 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001814 * @see #getAllocatableBytes(UUID, int)
1815 * @see #allocateBytes(UUID, long, int)
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001816 * @see #allocateBytes(FileDescriptor, long, int)
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001817 * @hide
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001818 */
1819 @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE)
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001820 @SystemApi
Jeff Sharkeyddff8072017-05-26 13:10:46 -06001821 public static final int FLAG_ALLOCATE_AGGRESSIVE = 1 << 0;
1822
1823 /**
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001824 * Flag indicating that a disk space allocation request should be allowed to
1825 * clear up to all reserved disk space.
Jeff Sharkeyddff8072017-05-26 13:10:46 -06001826 *
1827 * @hide
1828 */
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001829 public static final int FLAG_ALLOCATE_DEFY_ALL_RESERVED = 1 << 1;
1830
1831 /**
1832 * Flag indicating that a disk space allocation request should be allowed to
1833 * clear up to half of all reserved disk space.
1834 *
1835 * @hide
1836 */
1837 public static final int FLAG_ALLOCATE_DEFY_HALF_RESERVED = 1 << 2;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001838
1839 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -07001840 @IntDef(flag = true, prefix = { "FLAG_ALLOCATE_" }, value = {
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001841 FLAG_ALLOCATE_AGGRESSIVE,
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001842 FLAG_ALLOCATE_DEFY_ALL_RESERVED,
1843 FLAG_ALLOCATE_DEFY_HALF_RESERVED,
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001844 })
1845 @Retention(RetentionPolicy.SOURCE)
1846 public @interface AllocateFlags {}
1847
1848 /**
1849 * Return the maximum number of new bytes that your app can allocate for
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001850 * itself on the given storage volume. This value is typically larger than
1851 * {@link File#getUsableSpace()}, since the system may be willing to delete
1852 * cached files to satisfy an allocation request. You can then allocate
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001853 * space for yourself using {@link #allocateBytes(UUID, long)} or
1854 * {@link #allocateBytes(FileDescriptor, long)}.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001855 * <p>
1856 * This method is best used as a pre-flight check, such as deciding if there
1857 * is enough space to store an entire music album before you allocate space
1858 * for each audio file in the album. Attempts to allocate disk space beyond
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001859 * the returned value will fail.
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001860 * <p>
1861 * If the returned value is not large enough for the data you'd like to
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001862 * persist, you can launch {@link #ACTION_MANAGE_STORAGE} with the
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001863 * {@link #EXTRA_UUID} and {@link #EXTRA_REQUESTED_BYTES} options to help
1864 * involve the user in freeing up disk space.
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001865 * <p>
1866 * If you're progressively allocating an unbounded amount of storage space
1867 * (such as when recording a video) you should avoid calling this method
1868 * more than once every 30 seconds.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001869 * <p class="note">
1870 * Note: if your app uses the {@code android:sharedUserId} manifest feature,
1871 * then allocatable space for all packages in your shared UID is tracked
1872 * together as a single unit.
1873 * </p>
1874 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001875 * @param storageUuid the UUID of the storage volume where you're
1876 * considering allocating disk space, since allocatable space can
1877 * vary widely depending on the underlying storage device. The
1878 * UUID for a specific path can be obtained using
1879 * {@link #getUuidForPath(File)}.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001880 * @return the maximum number of new bytes that the calling app can allocate
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001881 * using {@link #allocateBytes(UUID, long)} or
1882 * {@link #allocateBytes(FileDescriptor, long)}.
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001883 * @throws IOException when the storage device isn't present, or when it
1884 * doesn't support allocating space.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001885 */
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001886 @WorkerThread
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001887 public @BytesLong long getAllocatableBytes(@NonNull UUID storageUuid)
1888 throws IOException {
1889 return getAllocatableBytes(storageUuid, 0);
1890 }
1891
1892 /** @hide */
1893 @SystemApi
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001894 @WorkerThread
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -06001895 @SuppressLint("Doclava125")
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001896 public long getAllocatableBytes(@NonNull UUID storageUuid,
1897 @RequiresPermission @AllocateFlags int flags) throws IOException {
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001898 try {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001899 return mStorageManager.getAllocatableBytes(convert(storageUuid), flags,
1900 mContext.getOpPackageName());
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001901 } catch (ParcelableException e) {
1902 e.maybeRethrow(IOException.class);
1903 throw new RuntimeException(e);
1904 } catch (RemoteException e) {
1905 throw e.rethrowFromSystemServer();
1906 }
1907 }
1908
1909 /**
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001910 * Allocate the requested number of bytes for your application to use on the
1911 * given storage volume. This will cause the system to delete any cached
1912 * files necessary to satisfy your request.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001913 * <p>
1914 * Attempts to allocate disk space beyond the value returned by
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001915 * {@link #getAllocatableBytes(UUID)} will fail.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001916 * <p>
1917 * Since multiple apps can be running simultaneously, this method may be
1918 * subject to race conditions. If possible, consider using
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001919 * {@link #allocateBytes(FileDescriptor, long)} which will guarantee
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001920 * that bytes are allocated to an opened file.
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001921 * <p>
1922 * If you're progressively allocating an unbounded amount of storage space
1923 * (such as when recording a video) you should avoid calling this method
1924 * more than once every 60 seconds.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001925 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001926 * @param storageUuid the UUID of the storage volume where you'd like to
1927 * allocate disk space. The UUID for a specific path can be
1928 * obtained using {@link #getUuidForPath(File)}.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001929 * @param bytes the number of bytes to allocate.
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001930 * @throws IOException when the storage device isn't present, or when it
1931 * doesn't support allocating space, or if the device had
1932 * trouble allocating the requested space.
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001933 * @see #getAllocatableBytes(UUID)
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001934 */
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001935 @WorkerThread
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001936 public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes)
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001937 throws IOException {
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001938 allocateBytes(storageUuid, bytes, 0);
1939 }
1940
1941 /** @hide */
1942 @SystemApi
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001943 @WorkerThread
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -06001944 @SuppressLint("Doclava125")
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001945 public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes,
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001946 @RequiresPermission @AllocateFlags int flags) throws IOException {
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001947 try {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001948 mStorageManager.allocateBytes(convert(storageUuid), bytes, flags,
1949 mContext.getOpPackageName());
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001950 } catch (ParcelableException e) {
1951 e.maybeRethrow(IOException.class);
1952 } catch (RemoteException e) {
1953 throw e.rethrowFromSystemServer();
1954 }
1955 }
1956
1957 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001958 * Allocate the requested number of bytes for your application to use in the
1959 * given open file. This will cause the system to delete any cached files
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001960 * necessary to satisfy your request.
1961 * <p>
1962 * Attempts to allocate disk space beyond the value returned by
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001963 * {@link #getAllocatableBytes(UUID)} will fail.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001964 * <p>
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001965 * This method guarantees that bytes have been allocated to the opened file,
1966 * otherwise it will throw if fast allocation is not possible. Fast
1967 * allocation is typically only supported in private app data directories,
1968 * and on shared/external storage devices which are emulated.
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001969 * <p>
1970 * If you're progressively allocating an unbounded amount of storage space
1971 * (such as when recording a video) you should avoid calling this method
1972 * more than once every 60 seconds.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001973 *
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001974 * @param fd the open file that you'd like to allocate disk space for.
1975 * @param bytes the number of bytes to allocate. This is the desired final
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001976 * size of the open file. If the open file is smaller than this
1977 * requested size, it will be extended without modifying any
1978 * existing contents. If the open file is larger than this
1979 * requested size, it will be truncated.
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001980 * @throws IOException when the storage device isn't present, or when it
1981 * doesn't support allocating space, or if the device had
1982 * trouble allocating the requested space.
Jeff Sharkey4233f032017-07-15 12:58:38 -06001983 * @see #isAllocationSupported(FileDescriptor)
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001984 * @see Environment#isExternalStorageEmulated(File)
1985 */
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001986 @WorkerThread
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001987 public void allocateBytes(FileDescriptor fd, @BytesLong long bytes) throws IOException {
1988 allocateBytes(fd, bytes, 0);
1989 }
1990
1991 /** @hide */
1992 @SystemApi
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001993 @WorkerThread
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -06001994 @SuppressLint("Doclava125")
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001995 public void allocateBytes(FileDescriptor fd, @BytesLong long bytes,
1996 @RequiresPermission @AllocateFlags int flags) throws IOException {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001997 final File file = ParcelFileDescriptor.getFile(fd);
Jeff Sharkey4233f032017-07-15 12:58:38 -06001998 final UUID uuid = getUuidForPath(file);
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001999 for (int i = 0; i < 3; i++) {
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07002000 try {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07002001 final long haveBytes = Os.fstat(fd).st_blocks * 512;
2002 final long needBytes = bytes - haveBytes;
2003
2004 if (needBytes > 0) {
Jeff Sharkey4233f032017-07-15 12:58:38 -06002005 allocateBytes(uuid, needBytes, flags);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07002006 }
2007
Jeff Sharkey4233f032017-07-15 12:58:38 -06002008 try {
2009 Os.posix_fallocate(fd, 0, bytes);
2010 return;
2011 } catch (ErrnoException e) {
2012 if (e.errno == OsConstants.ENOSYS || e.errno == OsConstants.ENOTSUP) {
2013 Log.w(TAG, "fallocate() not supported; falling back to ftruncate()");
2014 Os.ftruncate(fd, bytes);
2015 return;
2016 } else {
2017 throw e;
2018 }
2019 }
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07002020 } catch (ErrnoException e) {
2021 if (e.errno == OsConstants.ENOSPC) {
2022 Log.w(TAG, "Odd, not enough space; let's try again?");
2023 continue;
2024 }
2025 throw e.rethrowAsIOException();
2026 }
2027 }
2028 throw new IOException(
2029 "Well this is embarassing; we can't allocate " + bytes + " for " + file);
2030 }
2031
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06002032 private static final String XATTR_CACHE_GROUP = "user.cache_group";
Jeff Sharkey458428e2017-02-22 11:47:15 -07002033 private static final String XATTR_CACHE_TOMBSTONE = "user.cache_tombstone";
Jeff Sharkey9bed0702017-01-23 20:37:05 -07002034
2035 /** {@hide} */
2036 private static void setCacheBehavior(File path, String name, boolean enabled)
2037 throws IOException {
2038 if (!path.isDirectory()) {
2039 throw new IOException("Cache behavior can only be set on directories");
2040 }
2041 if (enabled) {
2042 try {
2043 Os.setxattr(path.getAbsolutePath(), name,
2044 "1".getBytes(StandardCharsets.UTF_8), 0);
2045 } catch (ErrnoException e) {
2046 throw e.rethrowAsIOException();
2047 }
2048 } else {
2049 try {
2050 Os.removexattr(path.getAbsolutePath(), name);
2051 } catch (ErrnoException e) {
2052 if (e.errno != OsConstants.ENODATA) {
2053 throw e.rethrowAsIOException();
2054 }
2055 }
2056 }
2057 }
2058
2059 /** {@hide} */
2060 private static boolean isCacheBehavior(File path, String name) throws IOException {
2061 try {
2062 Os.getxattr(path.getAbsolutePath(), name);
2063 return true;
2064 } catch (ErrnoException e) {
2065 if (e.errno != OsConstants.ENODATA) {
2066 throw e.rethrowAsIOException();
2067 } else {
2068 return false;
2069 }
2070 }
2071 }
2072
2073 /**
2074 * Enable or disable special cache behavior that treats this directory and
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06002075 * its contents as an entire group.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07002076 * <p>
2077 * When enabled and this directory is considered for automatic deletion by
2078 * the OS, all contained files will either be deleted together, or not at
2079 * all. This is useful when you have a directory that contains several
2080 * related metadata files that depend on each other, such as movie file and
2081 * a subtitle file.
2082 * <p>
2083 * When enabled, the <em>newest</em> {@link File#lastModified()} value of
2084 * any contained files is considered the modified time of the entire
2085 * directory.
2086 * <p>
2087 * This behavior can only be set on a directory, and it applies recursively
2088 * to all contained files and directories.
2089 */
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06002090 public void setCacheBehaviorGroup(File path, boolean group) throws IOException {
2091 setCacheBehavior(path, XATTR_CACHE_GROUP, group);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07002092 }
2093
2094 /**
2095 * Read the current value set by
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06002096 * {@link #setCacheBehaviorGroup(File, boolean)}.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07002097 */
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06002098 public boolean isCacheBehaviorGroup(File path) throws IOException {
2099 return isCacheBehavior(path, XATTR_CACHE_GROUP);
2100 }
2101
Jeff Sharkey9bed0702017-01-23 20:37:05 -07002102 /**
2103 * Enable or disable special cache behavior that leaves deleted cache files
2104 * intact as tombstones.
2105 * <p>
2106 * When enabled and a file contained in this directory is automatically
2107 * deleted by the OS, the file will be truncated to have a length of 0 bytes
2108 * instead of being fully deleted. This is useful if you need to distinguish
2109 * between a file that was deleted versus one that never existed.
2110 * <p>
2111 * This behavior can only be set on a directory, and it applies recursively
2112 * to all contained files and directories.
2113 * <p class="note">
2114 * Note: this behavior is ignored completely if the user explicitly requests
2115 * that all cached data be cleared.
2116 * </p>
2117 */
2118 public void setCacheBehaviorTombstone(File path, boolean tombstone) throws IOException {
Jeff Sharkey458428e2017-02-22 11:47:15 -07002119 setCacheBehavior(path, XATTR_CACHE_TOMBSTONE, tombstone);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07002120 }
2121
2122 /**
2123 * Read the current value set by
2124 * {@link #setCacheBehaviorTombstone(File, boolean)}.
2125 */
2126 public boolean isCacheBehaviorTombstone(File path) throws IOException {
Jeff Sharkey458428e2017-02-22 11:47:15 -07002127 return isCacheBehavior(path, XATTR_CACHE_TOMBSTONE);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07002128 }
2129
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06002130 /** {@hide} */
2131 public static UUID convert(String uuid) {
2132 if (Objects.equals(uuid, UUID_PRIVATE_INTERNAL)) {
2133 return UUID_DEFAULT;
2134 } else if (Objects.equals(uuid, UUID_PRIMARY_PHYSICAL)) {
2135 return UUID_PRIMARY_PHYSICAL_;
2136 } else if (Objects.equals(uuid, UUID_SYSTEM)) {
2137 return UUID_SYSTEM_;
2138 } else {
2139 return UUID.fromString(uuid);
2140 }
2141 }
2142
2143 /** {@hide} */
2144 public static String convert(UUID storageUuid) {
2145 if (UUID_DEFAULT.equals(storageUuid)) {
2146 return UUID_PRIVATE_INTERNAL;
2147 } else if (UUID_PRIMARY_PHYSICAL_.equals(storageUuid)) {
2148 return UUID_PRIMARY_PHYSICAL;
2149 } else if (UUID_SYSTEM_.equals(storageUuid)) {
2150 return UUID_SYSTEM;
2151 } else {
2152 return storageUuid.toString();
2153 }
2154 }
2155
Daichi Hirono9fb00182016-11-08 14:12:17 +09002156 private final Object mFuseAppLoopLock = new Object();
2157
2158 @GuardedBy("mFuseAppLoopLock")
2159 private @Nullable FuseAppLoop mFuseAppLoop = null;
2160
Paul Lawrencee8fdc542014-05-28 07:14:17 -07002161 /// Consts to match the password types in cryptfs.h
2162 /** @hide */
Mathew Inwood98e9ad12018-08-30 13:11:50 +01002163 @UnsupportedAppUsage
Jeff Sharkey43e12112017-09-12 16:31:45 -06002164 public static final int CRYPT_TYPE_PASSWORD = IVold.PASSWORD_TYPE_PASSWORD;
Paul Lawrencee8fdc542014-05-28 07:14:17 -07002165 /** @hide */
Mathew Inwood98e9ad12018-08-30 13:11:50 +01002166 @UnsupportedAppUsage
Jeff Sharkey43e12112017-09-12 16:31:45 -06002167 public static final int CRYPT_TYPE_DEFAULT = IVold.PASSWORD_TYPE_DEFAULT;
Paul Lawrencee8fdc542014-05-28 07:14:17 -07002168 /** @hide */
Jeff Sharkey43e12112017-09-12 16:31:45 -06002169 public static final int CRYPT_TYPE_PATTERN = IVold.PASSWORD_TYPE_PATTERN;
Paul Lawrencee8fdc542014-05-28 07:14:17 -07002170 /** @hide */
Jeff Sharkey43e12112017-09-12 16:31:45 -06002171 public static final int CRYPT_TYPE_PIN = IVold.PASSWORD_TYPE_PIN;
Elliott Hughesf839b4f2014-09-26 12:30:47 -07002172
Sudheer Shanka2250d562016-11-07 15:41:02 -08002173 // Constants for the data available via StorageManagerService.getField.
Elliott Hughesf839b4f2014-09-26 12:30:47 -07002174 /** @hide */
2175 public static final String SYSTEM_LOCALE_KEY = "SystemLocale";
2176 /** @hide */
2177 public static final String OWNER_INFO_KEY = "OwnerInfo";
2178 /** @hide */
2179 public static final String PATTERN_VISIBLE_KEY = "PatternVisible";
Paul Lawrenced8fdb332015-05-18 13:26:11 -07002180 /** @hide */
2181 public static final String PASSWORD_VISIBLE_KEY = "PasswordVisible";
San Mehatb1043402010-02-05 08:26:50 -08002182}