blob: 90a5f7660e0d97a7ae32675ca014a4f46e04cd27 [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 Sharkey1b8ef7e2015-04-03 17:14:45 -0700139
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700140 /** {@hide} */
Jeff Sharkey669e6b12018-10-27 17:58:44 -0600141 public static final String PROP_FORCE_AUDIO = "persist.fw.force_audio";
142 /** {@hide} */
143 public static final String PROP_FORCE_VIDEO = "persist.fw.force_video";
144 /** {@hide} */
145 public static final String PROP_FORCE_IMAGES = "persist.fw.force_images";
Jeff Sharkey669e6b12018-10-27 17:58:44 -0600146
147 /** {@hide} */
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700148 public static final String UUID_PRIVATE_INTERNAL = null;
149 /** {@hide} */
150 public static final String UUID_PRIMARY_PHYSICAL = "primary_physical";
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600151 /** {@hide} */
152 public static final String UUID_SYSTEM = "system";
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700153
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600154 // NOTE: UUID constants below are namespaced
155 // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad default
156 // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad primary_physical
157 // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad system
Daniel Nishi690346b2016-06-17 10:21:48 -0700158
159 /**
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600160 * UUID representing the default internal storage of this device which
161 * provides {@link Environment#getDataDirectory()}.
Daniel Nishi690346b2016-06-17 10:21:48 -0700162 * <p>
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600163 * This value is constant across all devices and it will never change, and
164 * thus it cannot be used to uniquely identify a particular physical device.
165 *
166 * @see #getUuidForPath(File)
Jeff Sharkeya4d34d92017-04-27 11:21:41 -0600167 * @see ApplicationInfo#storageUuid
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600168 */
169 public static final UUID UUID_DEFAULT = UUID
170 .fromString("41217664-9172-527a-b3d5-edabb50a7d69");
171
172 /** {@hide} */
173 public static final UUID UUID_PRIMARY_PHYSICAL_ = UUID
174 .fromString("0f95a519-dae7-5abf-9519-fbd6209e05fd");
175
176 /** {@hide} */
177 public static final UUID UUID_SYSTEM_ = UUID
178 .fromString("5d258386-e60d-59e3-826d-0089cdd42cc0");
179
180 /**
181 * Activity Action: Allows the user to manage their storage. This activity
182 * provides the ability to free up space on the device by deleting data such
183 * as apps.
Daniel Nishi690346b2016-06-17 10:21:48 -0700184 * <p>
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600185 * If the sending application has a specific storage device or allocation
186 * size in mind, they can optionally define {@link #EXTRA_UUID} or
187 * {@link #EXTRA_REQUESTED_BYTES}, respectively.
Jeff Sharkeyb31afd22017-06-12 14:17:10 -0600188 * <p>
189 * This intent should be launched using
190 * {@link Activity#startActivityForResult(Intent, int)} so that the user
191 * knows which app is requesting the storage space. The returned result will
192 * be {@link Activity#RESULT_OK} if the requested space was made available,
193 * or {@link Activity#RESULT_CANCELED} otherwise.
Daniel Nishi690346b2016-06-17 10:21:48 -0700194 */
195 @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600196 public static final String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
197
198 /**
199 * Extra {@link UUID} used to indicate the storage volume where an
200 * application is interested in allocating or managing disk space.
201 *
202 * @see #ACTION_MANAGE_STORAGE
203 * @see #UUID_DEFAULT
204 * @see #getUuidForPath(File)
Jeff Sharkeya4d34d92017-04-27 11:21:41 -0600205 * @see Intent#putExtra(String, java.io.Serializable)
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600206 */
207 public static final String EXTRA_UUID = "android.os.storage.extra.UUID";
208
209 /**
210 * Extra used to indicate the total size (in bytes) that an application is
211 * interested in allocating.
212 * <p>
213 * When defined, the management UI will help guide the user to free up
214 * enough disk space to reach this requested value.
215 *
216 * @see #ACTION_MANAGE_STORAGE
217 */
218 public static final String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES";
Daniel Nishi690346b2016-06-17 10:21:48 -0700219
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700220 /** {@hide} */
Jeff Sharkey901c0422018-04-20 13:11:20 -0600221 public static final int DEBUG_ADOPTABLE_FORCE_ON = 1 << 0;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800222 /** {@hide} */
Jeff Sharkey901c0422018-04-20 13:11:20 -0600223 public static final int DEBUG_ADOPTABLE_FORCE_OFF = 1 << 1;
Jeff Sharkey33dd1562016-04-07 11:05:33 -0600224 /** {@hide} */
Jeff Sharkey901c0422018-04-20 13:11:20 -0600225 public static final int DEBUG_EMULATE_FBE = 1 << 2;
Jeff Sharkey33dd1562016-04-07 11:05:33 -0600226 /** {@hide} */
Jeff Sharkey901c0422018-04-20 13:11:20 -0600227 public static final int DEBUG_SDCARDFS_FORCE_ON = 1 << 3;
Jeff Sharkeye53e2d92017-03-25 23:14:06 -0600228 /** {@hide} */
Jeff Sharkey901c0422018-04-20 13:11:20 -0600229 public static final int DEBUG_SDCARDFS_FORCE_OFF = 1 << 4;
230 /** {@hide} */
231 public static final int DEBUG_VIRTUAL_DISK = 1 << 5;
Sudheer Shankabe0febe2018-11-07 18:24:37 -0800232 /** {@hide} */
Jeff Sharkeyb0c363b22018-12-15 11:53:03 -0700233 public static final int DEBUG_ISOLATED_STORAGE_FORCE_ON = 1 << 6;
234 /** {@hide} */
235 public static final int DEBUG_ISOLATED_STORAGE_FORCE_OFF = 1 << 7;
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700236
Jeff Sharkey46349872015-07-28 10:49:47 -0700237 /** {@hide} */
Jeff Sharkey4e7a7652018-08-24 17:25:42 -0600238 public static final int FLAG_STORAGE_DE = IInstalld.FLAG_STORAGE_DE;
Jeff Sharkey47f71082016-02-01 17:03:54 -0700239 /** {@hide} */
Jeff Sharkey4e7a7652018-08-24 17:25:42 -0600240 public static final int FLAG_STORAGE_CE = IInstalld.FLAG_STORAGE_CE;
Jeff Sharkey47f71082016-02-01 17:03:54 -0700241
242 /** {@hide} */
243 public static final int FLAG_FOR_WRITE = 1 << 8;
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -0600244 /** {@hide} */
245 public static final int FLAG_REAL_STATE = 1 << 9;
246 /** {@hide} */
247 public static final int FLAG_INCLUDE_INVISIBLE = 1 << 10;
Jeff Sharkey46349872015-07-28 10:49:47 -0700248
Jeff Sharkey31d0b702016-11-21 14:16:53 -0700249 /** {@hide} */
Jeff Sharkey41cd6812017-09-11 10:32:17 -0600250 public static final int FSTRIM_FLAG_DEEP = IVold.FSTRIM_FLAG_DEEP_TRIM;
Jeff Sharkey31d0b702016-11-21 14:16:53 -0700251
Sudheer Shankaf7341142016-10-18 17:15:18 -0700252 /** @hide The volume is not encrypted. */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100253 @UnsupportedAppUsage
Jeff Sharkey43e12112017-09-12 16:31:45 -0600254 public static final int ENCRYPTION_STATE_NONE =
255 IVold.ENCRYPTION_STATE_NONE;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700256
257 /** @hide The volume has been encrypted succesfully. */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600258 public static final int ENCRYPTION_STATE_OK =
259 IVold.ENCRYPTION_STATE_OK;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700260
Jeff Sharkey43e12112017-09-12 16:31:45 -0600261 /** @hide The volume is in a bad state. */
262 public static final int ENCRYPTION_STATE_ERROR_UNKNOWN =
263 IVold.ENCRYPTION_STATE_ERROR_UNKNOWN;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700264
265 /** @hide Encryption is incomplete */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600266 public static final int ENCRYPTION_STATE_ERROR_INCOMPLETE =
267 IVold.ENCRYPTION_STATE_ERROR_INCOMPLETE;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700268
269 /** @hide Encryption is incomplete and irrecoverable */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600270 public static final int ENCRYPTION_STATE_ERROR_INCONSISTENT =
271 IVold.ENCRYPTION_STATE_ERROR_INCONSISTENT;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700272
273 /** @hide Underlying data is corrupt */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600274 public static final int ENCRYPTION_STATE_ERROR_CORRUPT =
275 IVold.ENCRYPTION_STATE_ERROR_CORRUPT;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700276
Sudheer Shankad68bd602018-11-13 17:43:39 -0800277 /** @hide Prefix used in sandboxIds for apps with sharedUserIds */
278 public static final String SHARED_SANDBOX_PREFIX = "shared-";
279
Sudheer Shanka2250d562016-11-07 15:41:02 -0800280 private static volatile IStorageManager sStorageManager = null;
Felipe Leme179923a2016-07-19 09:33:31 -0700281
Jeff Sharkey48877892015-03-18 11:27:19 -0700282 private final Context mContext;
Jeff Sharkeybe722152013-02-15 16:56:38 -0800283 private final ContentResolver mResolver;
284
Sudheer Shanka2250d562016-11-07 15:41:02 -0800285 private final IStorageManager mStorageManager;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700286 private final Looper mLooper;
287 private final AtomicInteger mNextNonce = new AtomicInteger(0);
San Mehatb1043402010-02-05 08:26:50 -0800288
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700289 private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>();
San Mehatb1043402010-02-05 08:26:50 -0800290
Sudheer Shanka2250d562016-11-07 15:41:02 -0800291 private static class StorageEventListenerDelegate extends IStorageEventListener.Stub implements
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700292 Handler.Callback {
293 private static final int MSG_STORAGE_STATE_CHANGED = 1;
294 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700295 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
296 private static final int MSG_VOLUME_FORGOTTEN = 4;
297 private static final int MSG_DISK_SCANNED = 5;
Makoto Onuki9dc575d2015-06-12 16:10:25 -0700298 private static final int MSG_DISK_DESTROYED = 6;
San Mehatb1043402010-02-05 08:26:50 -0800299
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700300 final StorageEventListener mCallback;
301 final Handler mHandler;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700302
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700303 public StorageEventListenerDelegate(StorageEventListener callback, Looper looper) {
304 mCallback = callback;
305 mHandler = new Handler(looper, this);
San Mehatb1043402010-02-05 08:26:50 -0800306 }
307
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700308 @Override
309 public boolean handleMessage(Message msg) {
310 final SomeArgs args = (SomeArgs) msg.obj;
311 switch (msg.what) {
312 case MSG_STORAGE_STATE_CHANGED:
313 mCallback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
314 (String) args.arg3);
315 args.recycle();
316 return true;
317 case MSG_VOLUME_STATE_CHANGED:
318 mCallback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
319 args.recycle();
320 return true;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700321 case MSG_VOLUME_RECORD_CHANGED:
322 mCallback.onVolumeRecordChanged((VolumeRecord) args.arg1);
323 args.recycle();
324 return true;
325 case MSG_VOLUME_FORGOTTEN:
326 mCallback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700327 args.recycle();
328 return true;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700329 case MSG_DISK_SCANNED:
330 mCallback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700331 args.recycle();
332 return true;
Makoto Onuki9dc575d2015-06-12 16:10:25 -0700333 case MSG_DISK_DESTROYED:
334 mCallback.onDiskDestroyed((DiskInfo) args.arg1);
335 args.recycle();
336 return true;
San Mehatb1043402010-02-05 08:26:50 -0800337 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700338 args.recycle();
339 return false;
340 }
341
342 @Override
343 public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException {
344 // Ignored
345 }
346
347 @Override
348 public void onStorageStateChanged(String path, String oldState, String newState) {
349 final SomeArgs args = SomeArgs.obtain();
350 args.arg1 = path;
351 args.arg2 = oldState;
352 args.arg3 = newState;
353 mHandler.obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
354 }
355
356 @Override
357 public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
358 final SomeArgs args = SomeArgs.obtain();
359 args.arg1 = vol;
360 args.argi2 = oldState;
361 args.argi3 = newState;
362 mHandler.obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
San Mehatb1043402010-02-05 08:26:50 -0800363 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700364
365 @Override
Jeff Sharkey50a05452015-04-29 11:24:52 -0700366 public void onVolumeRecordChanged(VolumeRecord rec) {
367 final SomeArgs args = SomeArgs.obtain();
368 args.arg1 = rec;
369 mHandler.obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
370 }
371
372 @Override
373 public void onVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700374 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700375 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700376 mHandler.obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700377 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700378
379 @Override
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700380 public void onDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700381 final SomeArgs args = SomeArgs.obtain();
382 args.arg1 = disk;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700383 args.argi2 = volumeCount;
384 mHandler.obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700385 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -0700386
387 @Override
388 public void onDiskDestroyed(DiskInfo disk) throws RemoteException {
389 final SomeArgs args = SomeArgs.obtain();
390 args.arg1 = disk;
391 mHandler.obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
392 }
San Mehatb1043402010-02-05 08:26:50 -0800393 }
394
395 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700396 * Binder listener for OBB action results.
397 */
Kenny Root05105f72010-09-22 17:29:43 -0700398 private final ObbActionListener mObbActionListener = new ObbActionListener();
399
400 private class ObbActionListener extends IObbActionListener.Stub {
Gilles Debunne37051cd2011-05-25 16:27:13 -0700401 @SuppressWarnings("hiding")
Kenny Rootaf9d6672010-10-08 09:21:39 -0700402 private SparseArray<ObbListenerDelegate> mListeners = new SparseArray<ObbListenerDelegate>();
Kenny Root05105f72010-09-22 17:29:43 -0700403
Kenny Roota02b8b02010-08-05 16:14:17 -0700404 @Override
Gilles Debunne37051cd2011-05-25 16:27:13 -0700405 public void onObbResult(String filename, int nonce, int status) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700406 final ObbListenerDelegate delegate;
Kenny Root05105f72010-09-22 17:29:43 -0700407 synchronized (mListeners) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700408 delegate = mListeners.get(nonce);
409 if (delegate != null) {
410 mListeners.remove(nonce);
Kenny Root05105f72010-09-22 17:29:43 -0700411 }
412 }
Kenny Rootaf9d6672010-10-08 09:21:39 -0700413
414 if (delegate != null) {
415 delegate.sendObbStateChanged(filename, status);
416 }
Kenny Root05105f72010-09-22 17:29:43 -0700417 }
418
Kenny Rootaf9d6672010-10-08 09:21:39 -0700419 public int addListener(OnObbStateChangeListener listener) {
420 final ObbListenerDelegate delegate = new ObbListenerDelegate(listener);
Kenny Root05105f72010-09-22 17:29:43 -0700421
422 synchronized (mListeners) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700423 mListeners.put(delegate.nonce, delegate);
Kenny Root05105f72010-09-22 17:29:43 -0700424 }
Kenny Rootaf9d6672010-10-08 09:21:39 -0700425
426 return delegate.nonce;
Kenny Root05105f72010-09-22 17:29:43 -0700427 }
428 }
429
Kenny Rootaf9d6672010-10-08 09:21:39 -0700430 private int getNextNonce() {
431 return mNextNonce.getAndIncrement();
432 }
433
Kenny Root05105f72010-09-22 17:29:43 -0700434 /**
435 * Private class containing sender and receiver code for StorageEvents.
436 */
437 private class ObbListenerDelegate {
438 private final WeakReference<OnObbStateChangeListener> mObbEventListenerRef;
439 private final Handler mHandler;
440
Kenny Rootaf9d6672010-10-08 09:21:39 -0700441 private final int nonce;
442
Kenny Root05105f72010-09-22 17:29:43 -0700443 ObbListenerDelegate(OnObbStateChangeListener listener) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700444 nonce = getNextNonce();
Kenny Root05105f72010-09-22 17:29:43 -0700445 mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700446 mHandler = new Handler(mLooper) {
Kenny Root05105f72010-09-22 17:29:43 -0700447 @Override
448 public void handleMessage(Message msg) {
Gilles Debunne37051cd2011-05-25 16:27:13 -0700449 final OnObbStateChangeListener changeListener = getListener();
450 if (changeListener == null) {
Kenny Root05105f72010-09-22 17:29:43 -0700451 return;
452 }
453
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700454 changeListener.onObbStateChange((String) msg.obj, msg.arg1);
Kenny Root05105f72010-09-22 17:29:43 -0700455 }
456 };
457 }
458
459 OnObbStateChangeListener getListener() {
460 if (mObbEventListenerRef == null) {
461 return null;
462 }
463 return mObbEventListenerRef.get();
464 }
465
Kenny Rootaf9d6672010-10-08 09:21:39 -0700466 void sendObbStateChanged(String path, int state) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700467 mHandler.obtainMessage(0, state, 0, path).sendToTarget();
San Mehatb1043402010-02-05 08:26:50 -0800468 }
469 }
470
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700471 /** {@hide} */
Jeff Sharkey50a05452015-04-29 11:24:52 -0700472 @Deprecated
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100473 @UnsupportedAppUsage
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700474 public static StorageManager from(Context context) {
Jeff Sharkey50a05452015-04-29 11:24:52 -0700475 return context.getSystemService(StorageManager.class);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700476 }
477
San Mehatb1043402010-02-05 08:26:50 -0800478 /**
479 * Constructs a StorageManager object through which an application can
480 * can communicate with the systems mount service.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900481 *
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600482 * @param looper The {@link android.os.Looper} which events will be received on.
San Mehatb1043402010-02-05 08:26:50 -0800483 *
484 * <p>Applications can get instance of this class by calling
485 * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
486 * of {@link android.content.Context#STORAGE_SERVICE}.
487 *
488 * @hide
489 */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100490 @UnsupportedAppUsage
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600491 public StorageManager(Context context, Looper looper) throws ServiceNotFoundException {
Jeff Sharkey48877892015-03-18 11:27:19 -0700492 mContext = context;
493 mResolver = context.getContentResolver();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700494 mLooper = looper;
Sudheer Shanka2250d562016-11-07 15:41:02 -0800495 mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getServiceOrThrow("mount"));
San Mehatb1043402010-02-05 08:26:50 -0800496 }
497
San Mehatb1043402010-02-05 08:26:50 -0800498 /**
499 * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}.
500 *
501 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
502 *
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800503 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800504 */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100505 @UnsupportedAppUsage
San Mehatb1043402010-02-05 08:26:50 -0800506 public void registerListener(StorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700507 synchronized (mDelegates) {
508 final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(listener,
509 mLooper);
510 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800511 mStorageManager.registerListener(delegate);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700512 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700513 throw e.rethrowFromSystemServer();
Chuanxia Dong6614bb62012-05-29 12:28:24 +0800514 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700515 mDelegates.add(delegate);
San Mehatb1043402010-02-05 08:26:50 -0800516 }
517 }
518
519 /**
520 * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}.
521 *
522 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
523 *
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800524 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800525 */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100526 @UnsupportedAppUsage
San Mehatb1043402010-02-05 08:26:50 -0800527 public void unregisterListener(StorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700528 synchronized (mDelegates) {
529 for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) {
530 final StorageEventListenerDelegate delegate = i.next();
531 if (delegate.mCallback == listener) {
532 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800533 mStorageManager.unregisterListener(delegate);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700534 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700535 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700536 }
537 i.remove();
538 }
539 }
San Mehatb1043402010-02-05 08:26:50 -0800540 }
San Mehatb1043402010-02-05 08:26:50 -0800541 }
542
543 /**
544 * Enables USB Mass Storage (UMS) on the device.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800545 *
546 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800547 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700548 @Deprecated
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100549 @UnsupportedAppUsage
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800550 public void enableUsbMassStorage() {
San Mehatb1043402010-02-05 08:26:50 -0800551 }
552
553 /**
554 * Disables USB Mass Storage (UMS) on the device.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800555 *
556 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800557 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700558 @Deprecated
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100559 @UnsupportedAppUsage
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800560 public void disableUsbMassStorage() {
San Mehatb1043402010-02-05 08:26:50 -0800561 }
562
563 /**
564 * Query if a USB Mass Storage (UMS) host is connected.
565 * @return true if UMS host is connected.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800566 *
567 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800568 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700569 @Deprecated
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100570 @UnsupportedAppUsage
San Mehatb1043402010-02-05 08:26:50 -0800571 public boolean isUsbMassStorageConnected() {
San Mehatb1043402010-02-05 08:26:50 -0800572 return false;
573 }
574
575 /**
576 * Query if a USB Mass Storage (UMS) is enabled on the device.
577 * @return true if UMS host is enabled.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800578 *
579 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800580 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700581 @Deprecated
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100582 @UnsupportedAppUsage
San Mehatb1043402010-02-05 08:26:50 -0800583 public boolean isUsbMassStorageEnabled() {
San Mehatb1043402010-02-05 08:26:50 -0800584 return false;
585 }
Kenny Root02c87302010-07-01 08:10:18 -0700586
587 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700588 * Mount an Opaque Binary Blob (OBB) file. If a <code>key</code> is
589 * specified, it is supplied to the mounting process to be used in any
590 * encryption used in the OBB.
591 * <p>
Kenny Root05105f72010-09-22 17:29:43 -0700592 * The OBB will remain mounted for as long as the StorageManager reference
593 * is held by the application. As soon as this reference is lost, the OBBs
Kenny Rootaf9d6672010-10-08 09:21:39 -0700594 * in use will be unmounted. The {@link OnObbStateChangeListener} registered
595 * with this call will receive the success or failure of this operation.
Kenny Root05105f72010-09-22 17:29:43 -0700596 * <p>
Kenny Roota02b8b02010-08-05 16:14:17 -0700597 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
598 * file matches a package ID that is owned by the calling program's UID.
Kenny Root05105f72010-09-22 17:29:43 -0700599 * That is, shared UID applications can attempt to mount any other
Kenny Roota02b8b02010-08-05 16:14:17 -0700600 * application's OBB that shares its UID.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900601 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700602 * @param rawPath the path to the OBB file
Kenny Root05105f72010-09-22 17:29:43 -0700603 * @param key secret used to encrypt the OBB; may be <code>null</code> if no
604 * encryption was used on the OBB.
Kenny Rootaf9d6672010-10-08 09:21:39 -0700605 * @param listener will receive the success or failure of the operation
Kenny Roota02b8b02010-08-05 16:14:17 -0700606 * @return whether the mount call was successfully queued or not
Kenny Root02c87302010-07-01 08:10:18 -0700607 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700608 public boolean mountObb(String rawPath, String key, OnObbStateChangeListener listener) {
609 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
610 Preconditions.checkNotNull(listener, "listener cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700611
Kenny Root02c87302010-07-01 08:10:18 -0700612 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700613 final String canonicalPath = new File(rawPath).getCanonicalPath();
Kenny Rootaf9d6672010-10-08 09:21:39 -0700614 final int nonce = mObbActionListener.addListener(listener);
Sudheer Shanka25469aa2018-08-27 15:50:23 -0700615 mStorageManager.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce,
616 getObbInfo(canonicalPath));
Kenny Roota02b8b02010-08-05 16:14:17 -0700617 return true;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700618 } catch (IOException e) {
619 throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e);
Kenny Root02c87302010-07-01 08:10:18 -0700620 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700621 throw e.rethrowFromSystemServer();
Kenny Root02c87302010-07-01 08:10:18 -0700622 }
Kenny Root02c87302010-07-01 08:10:18 -0700623 }
624
Sudheer Shanka25469aa2018-08-27 15:50:23 -0700625 private ObbInfo getObbInfo(String canonicalPath) {
626 try {
627 final ObbInfo obbInfo = ObbScanner.getObbInfo(canonicalPath);
628 return obbInfo;
629 } catch (IOException e) {
630 throw new IllegalArgumentException("Couldn't get OBB info for " + canonicalPath, e);
631 }
632 }
633
Kenny Root02c87302010-07-01 08:10:18 -0700634 /**
Kenny Root05105f72010-09-22 17:29:43 -0700635 * Unmount an Opaque Binary Blob (OBB) file asynchronously. If the
636 * <code>force</code> flag is true, it will kill any application needed to
637 * unmount the given OBB (even the calling application).
638 * <p>
Kenny Rootaf9d6672010-10-08 09:21:39 -0700639 * The {@link OnObbStateChangeListener} registered with this call will
640 * receive the success or failure of this operation.
Kenny Roota02b8b02010-08-05 16:14:17 -0700641 * <p>
642 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
643 * file matches a package ID that is owned by the calling program's UID.
644 * That is, shared UID applications can obtain access to any other
645 * application's OBB that shares its UID.
Kenny Root02ca31f2010-08-12 07:36:02 -0700646 * <p>
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900647 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700648 * @param rawPath path to the OBB file
Kenny Roota02b8b02010-08-05 16:14:17 -0700649 * @param force whether to kill any programs using this in order to unmount
650 * it
Kenny Rootaf9d6672010-10-08 09:21:39 -0700651 * @param listener will receive the success or failure of the operation
Kenny Roota02b8b02010-08-05 16:14:17 -0700652 * @return whether the unmount call was successfully queued or not
Kenny Root02c87302010-07-01 08:10:18 -0700653 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700654 public boolean unmountObb(String rawPath, boolean force, OnObbStateChangeListener listener) {
655 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
656 Preconditions.checkNotNull(listener, "listener cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700657
Kenny Root02c87302010-07-01 08:10:18 -0700658 try {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700659 final int nonce = mObbActionListener.addListener(listener);
Sudheer Shanka2250d562016-11-07 15:41:02 -0800660 mStorageManager.unmountObb(rawPath, force, mObbActionListener, nonce);
Kenny Roota02b8b02010-08-05 16:14:17 -0700661 return true;
Kenny Root02c87302010-07-01 08:10:18 -0700662 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700663 throw e.rethrowFromSystemServer();
Kenny Root02c87302010-07-01 08:10:18 -0700664 }
Kenny Root02c87302010-07-01 08:10:18 -0700665 }
666
Kenny Roota02b8b02010-08-05 16:14:17 -0700667 /**
668 * Check whether an Opaque Binary Blob (OBB) is mounted or not.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900669 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700670 * @param rawPath path to OBB image
Kenny Roota02b8b02010-08-05 16:14:17 -0700671 * @return true if OBB is mounted; false if not mounted or on error
672 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700673 public boolean isObbMounted(String rawPath) {
674 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700675
Kenny Root02c87302010-07-01 08:10:18 -0700676 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800677 return mStorageManager.isObbMounted(rawPath);
Kenny Root02c87302010-07-01 08:10:18 -0700678 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700679 throw e.rethrowFromSystemServer();
Kenny Root02c87302010-07-01 08:10:18 -0700680 }
Kenny Root02c87302010-07-01 08:10:18 -0700681 }
682
683 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700684 * Check the mounted path of an Opaque Binary Blob (OBB) file. This will
685 * give you the path to where you can obtain access to the internals of the
686 * OBB.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900687 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700688 * @param rawPath path to OBB image
Kenny Roota02b8b02010-08-05 16:14:17 -0700689 * @return absolute path to mounted OBB image data or <code>null</code> if
690 * not mounted or exception encountered trying to read status
Kenny Root02c87302010-07-01 08:10:18 -0700691 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700692 public String getMountedObbPath(String rawPath) {
693 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700694
Kenny Root02c87302010-07-01 08:10:18 -0700695 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800696 return mStorageManager.getMountedObbPath(rawPath);
Kenny Root02c87302010-07-01 08:10:18 -0700697 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700698 throw e.rethrowFromSystemServer();
Kenny Root02c87302010-07-01 08:10:18 -0700699 }
Kenny Root02c87302010-07-01 08:10:18 -0700700 }
Mike Lockwoodd967f462011-03-24 08:12:30 -0700701
Jeff Sharkey48877892015-03-18 11:27:19 -0700702 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100703 @UnsupportedAppUsage
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700704 public @NonNull List<DiskInfo> getDisks() {
705 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800706 return Arrays.asList(mStorageManager.getDisks());
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700707 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700708 throw e.rethrowFromSystemServer();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700709 }
710 }
711
712 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100713 @UnsupportedAppUsage
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700714 public @Nullable DiskInfo findDiskById(String id) {
715 Preconditions.checkNotNull(id);
716 // TODO; go directly to service to make this faster
717 for (DiskInfo disk : getDisks()) {
718 if (Objects.equals(disk.id, id)) {
719 return disk;
720 }
721 }
722 return null;
723 }
724
725 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100726 @UnsupportedAppUsage
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700727 public @Nullable VolumeInfo findVolumeById(String id) {
728 Preconditions.checkNotNull(id);
729 // TODO; go directly to service to make this faster
730 for (VolumeInfo vol : getVolumes()) {
731 if (Objects.equals(vol.id, id)) {
732 return vol;
733 }
734 }
735 return null;
736 }
737
738 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100739 @UnsupportedAppUsage
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700740 public @Nullable VolumeInfo findVolumeByUuid(String fsUuid) {
741 Preconditions.checkNotNull(fsUuid);
742 // TODO; go directly to service to make this faster
743 for (VolumeInfo vol : getVolumes()) {
744 if (Objects.equals(vol.fsUuid, fsUuid)) {
745 return vol;
746 }
747 }
748 return null;
749 }
750
751 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700752 public @Nullable VolumeRecord findRecordByUuid(String fsUuid) {
753 Preconditions.checkNotNull(fsUuid);
754 // TODO; go directly to service to make this faster
755 for (VolumeRecord rec : getVolumeRecords()) {
756 if (Objects.equals(rec.fsUuid, fsUuid)) {
757 return rec;
758 }
759 }
760 return null;
761 }
762
763 /** {@hide} */
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700764 public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700765 if (emulatedVol != null) {
766 return findVolumeById(emulatedVol.getId().replace("emulated", "private"));
767 } else {
768 return null;
769 }
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700770 }
771
772 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100773 @UnsupportedAppUsage
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700774 public @Nullable VolumeInfo findEmulatedForPrivate(VolumeInfo privateVol) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700775 if (privateVol != null) {
776 return findVolumeById(privateVol.getId().replace("private", "emulated"));
777 } else {
778 return null;
779 }
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700780 }
781
782 /** {@hide} */
Jeff Sharkey50a05452015-04-29 11:24:52 -0700783 public @Nullable VolumeInfo findVolumeByQualifiedUuid(String volumeUuid) {
784 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
785 return findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL);
786 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
787 return getPrimaryPhysicalVolume();
788 } else {
789 return findVolumeByUuid(volumeUuid);
790 }
791 }
792
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600793 /**
794 * Return a UUID identifying the storage volume that hosts the given
795 * filesystem path.
796 * <p>
797 * If this path is hosted by the default internal storage of the device at
798 * {@link Environment#getDataDirectory()}, the returned value will be
799 * {@link #UUID_DEFAULT}.
800 *
Jeff Sharkey4233f032017-07-15 12:58:38 -0600801 * @throws IOException when the storage device hosting the given path isn't
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600802 * present, or when it doesn't have a valid UUID.
803 */
804 public @NonNull UUID getUuidForPath(@NonNull File path) throws IOException {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700805 Preconditions.checkNotNull(path);
Jeff Sharkey00347882017-04-17 16:44:12 -0600806 final String pathString = path.getCanonicalPath();
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700807 if (FileUtils.contains(Environment.getDataDirectory().getAbsolutePath(), pathString)) {
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600808 return UUID_DEFAULT;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700809 }
810 try {
811 for (VolumeInfo vol : mStorageManager.getVolumes(0)) {
Jeff Sharkey18f32502018-03-29 14:29:27 -0600812 if (vol.path != null && FileUtils.contains(vol.path, pathString)
Risan05c41e62018-10-29 08:57:43 +0900813 && vol.type != VolumeInfo.TYPE_PUBLIC && vol.type != VolumeInfo.TYPE_STUB) {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700814 // TODO: verify that emulated adopted devices have UUID of
815 // underlying volume
Jeff Sharkey18f32502018-03-29 14:29:27 -0600816 try {
817 return convert(vol.fsUuid);
818 } catch (IllegalArgumentException e) {
819 continue;
820 }
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700821 }
822 }
823 } catch (RemoteException e) {
824 throw e.rethrowFromSystemServer();
825 }
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600826 throw new FileNotFoundException("Failed to find a storage device for " + path);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700827 }
828
829 /** {@hide} */
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600830 public @NonNull File findPathForUuid(String volumeUuid) throws FileNotFoundException {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700831 final VolumeInfo vol = findVolumeByQualifiedUuid(volumeUuid);
832 if (vol != null) {
833 return vol.getPath();
834 }
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600835 throw new FileNotFoundException("Failed to find a storage device for " + volumeUuid);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700836 }
837
Jeff Sharkey4233f032017-07-15 12:58:38 -0600838 /**
839 * Test if the given file descriptor supports allocation of disk space using
840 * {@link #allocateBytes(FileDescriptor, long)}.
841 */
842 public boolean isAllocationSupported(@NonNull FileDescriptor fd) {
843 try {
844 getUuidForPath(ParcelFileDescriptor.getFile(fd));
845 return true;
846 } catch (IOException e) {
847 return false;
848 }
849 }
850
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700851 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100852 @UnsupportedAppUsage
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700853 public @NonNull List<VolumeInfo> getVolumes() {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700854 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800855 return Arrays.asList(mStorageManager.getVolumes(0));
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700856 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700857 throw e.rethrowFromSystemServer();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700858 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700859 }
860
861 /** {@hide} */
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700862 public @NonNull List<VolumeInfo> getWritablePrivateVolumes() {
863 try {
864 final ArrayList<VolumeInfo> res = new ArrayList<>();
Sudheer Shanka2250d562016-11-07 15:41:02 -0800865 for (VolumeInfo vol : mStorageManager.getVolumes(0)) {
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700866 if (vol.getType() == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) {
867 res.add(vol);
868 }
869 }
870 return res;
871 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700872 throw e.rethrowFromSystemServer();
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700873 }
874 }
875
876 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700877 public @NonNull List<VolumeRecord> getVolumeRecords() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700878 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800879 return Arrays.asList(mStorageManager.getVolumeRecords(0));
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700880 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700881 throw e.rethrowFromSystemServer();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700882 }
883 }
884
885 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100886 @UnsupportedAppUsage
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700887 public @Nullable String getBestVolumeDescription(VolumeInfo vol) {
Jeff Sharkey50a05452015-04-29 11:24:52 -0700888 if (vol == null) return null;
889
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700890 // Nickname always takes precedence when defined
891 if (!TextUtils.isEmpty(vol.fsUuid)) {
892 final VolumeRecord rec = findRecordByUuid(vol.fsUuid);
Jeff Sharkeyc8406812015-05-04 12:04:09 -0700893 if (rec != null && !TextUtils.isEmpty(rec.nickname)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700894 return rec.nickname;
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700895 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700896 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700897
898 if (!TextUtils.isEmpty(vol.getDescription())) {
899 return vol.getDescription();
900 }
901
902 if (vol.disk != null) {
903 return vol.disk.getDescription();
904 }
905
906 return null;
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700907 }
908
909 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100910 @UnsupportedAppUsage
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700911 public @Nullable VolumeInfo getPrimaryPhysicalVolume() {
912 final List<VolumeInfo> vols = getVolumes();
913 for (VolumeInfo vol : vols) {
914 if (vol.isPrimaryPhysical()) {
915 return vol;
916 }
917 }
918 return null;
919 }
920
921 /** {@hide} */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700922 public void mount(String volId) {
923 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800924 mStorageManager.mount(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700925 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700926 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700927 }
928 }
929
930 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100931 @UnsupportedAppUsage
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700932 public void unmount(String volId) {
933 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800934 mStorageManager.unmount(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700935 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700936 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700937 }
938 }
939
940 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100941 @UnsupportedAppUsage
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700942 public void format(String volId) {
943 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800944 mStorageManager.format(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700945 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700946 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700947 }
948 }
949
950 /** {@hide} */
Jeff Sharkey7e19f532017-11-06 13:54:11 -0700951 @Deprecated
Jeff Sharkey9756d752015-05-14 21:07:42 -0700952 public long benchmark(String volId) {
Jeff Sharkey7e19f532017-11-06 13:54:11 -0700953 final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
954 benchmark(volId, new IVoldTaskListener.Stub() {
955 @Override
956 public void onStatus(int status, PersistableBundle extras) {
957 // Ignored
958 }
959
960 @Override
961 public void onFinished(int status, PersistableBundle extras) {
962 result.complete(extras);
963 }
964 });
Jeff Sharkey9756d752015-05-14 21:07:42 -0700965 try {
Jeff Sharkey7e19f532017-11-06 13:54:11 -0700966 // Convert ms to ns
967 return result.get(3, TimeUnit.MINUTES).getLong("run", Long.MAX_VALUE) * 1000000;
968 } catch (Exception e) {
969 return Long.MAX_VALUE;
970 }
971 }
972
973 /** {@hide} */
974 public void benchmark(String volId, IVoldTaskListener listener) {
975 try {
976 mStorageManager.benchmark(volId, listener);
Jeff Sharkey9756d752015-05-14 21:07:42 -0700977 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700978 throw e.rethrowFromSystemServer();
Jeff Sharkey9756d752015-05-14 21:07:42 -0700979 }
980 }
981
982 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +0100983 @UnsupportedAppUsage
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700984 public void partitionPublic(String diskId) {
985 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800986 mStorageManager.partitionPublic(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700987 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700988 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700989 }
990 }
991
992 /** {@hide} */
993 public void partitionPrivate(String diskId) {
994 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800995 mStorageManager.partitionPrivate(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700996 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700997 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700998 }
999 }
1000
1001 /** {@hide} */
1002 public void partitionMixed(String diskId, int ratio) {
1003 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001004 mStorageManager.partitionMixed(diskId, ratio);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001005 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001006 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001007 }
1008 }
1009
1010 /** {@hide} */
Jeff Sharkeyb42d6942015-04-28 22:25:26 -07001011 public void wipeAdoptableDisks() {
1012 // We only wipe devices in "adoptable" locations, which are in a
1013 // long-term stable slot/location on the device, where apps have a
1014 // reasonable chance of storing sensitive data. (Apps need to go through
1015 // SAF to write to transient volumes.)
1016 final List<DiskInfo> disks = getDisks();
1017 for (DiskInfo disk : disks) {
1018 final String diskId = disk.getId();
1019 if (disk.isAdoptable()) {
1020 Slog.d(TAG, "Found adoptable " + diskId + "; wiping");
1021 try {
1022 // TODO: switch to explicit wipe command when we have it,
1023 // for now rely on the fact that vfat format does a wipe
Sudheer Shanka2250d562016-11-07 15:41:02 -08001024 mStorageManager.partitionPublic(diskId);
Jeff Sharkeyb42d6942015-04-28 22:25:26 -07001025 } catch (Exception e) {
1026 Slog.w(TAG, "Failed to wipe " + diskId + ", but soldiering onward", e);
1027 }
1028 } else {
1029 Slog.d(TAG, "Ignorning non-adoptable disk " + disk.getId());
1030 }
1031 }
1032 }
1033
1034 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001035 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001036 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001037 mStorageManager.setVolumeNickname(fsUuid, nickname);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001038 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001039 throw e.rethrowFromSystemServer();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001040 }
1041 }
1042
1043 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001044 public void setVolumeInited(String fsUuid, boolean inited) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001045 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001046 mStorageManager.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0,
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001047 VolumeRecord.USER_FLAG_INITED);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001048 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001049 throw e.rethrowFromSystemServer();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001050 }
1051 }
1052
1053 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001054 public void setVolumeSnoozed(String fsUuid, boolean snoozed) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001055 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001056 mStorageManager.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0,
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001057 VolumeRecord.USER_FLAG_SNOOZED);
1058 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001059 throw e.rethrowFromSystemServer();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001060 }
1061 }
1062
1063 /** {@hide} */
1064 public void forgetVolume(String fsUuid) {
1065 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001066 mStorageManager.forgetVolume(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001067 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001068 throw e.rethrowFromSystemServer();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001069 }
1070 }
1071
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001072 /**
1073 * This is not the API you're looking for.
1074 *
1075 * @see PackageManager#getPrimaryStorageCurrentVolume()
1076 * @hide
1077 */
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001078 public String getPrimaryStorageUuid() {
1079 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001080 return mStorageManager.getPrimaryStorageUuid();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001081 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001082 throw e.rethrowFromSystemServer();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001083 }
1084 }
1085
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001086 /**
1087 * This is not the API you're looking for.
1088 *
1089 * @see PackageManager#movePrimaryStorage(VolumeInfo)
1090 * @hide
1091 */
1092 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001093 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001094 mStorageManager.setPrimaryStorageUuid(volumeUuid, callback);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001095 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001096 throw e.rethrowFromSystemServer();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001097 }
1098 }
1099
Felipe Lemec250e452016-04-11 18:44:33 -07001100 /**
Jeff Sharkeyf8fa9402019-02-18 13:23:51 -07001101 * Return the {@link StorageVolume} that contains the given file, or
1102 * {@code null} if none.
Felipe Lemec250e452016-04-11 18:44:33 -07001103 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001104 public @Nullable StorageVolume getStorageVolume(File file) {
1105 return getStorageVolume(getVolumeList(), file);
1106 }
1107
Jeff Sharkeyf8fa9402019-02-18 13:23:51 -07001108 /**
1109 * Return the {@link StorageVolume} that contains the given
1110 * {@link MediaStore} item.
1111 */
1112 public @NonNull StorageVolume getStorageVolume(@NonNull Uri uri) {
1113 final String volumeName = MediaStore.getVolumeName(uri);
1114 switch (volumeName) {
1115 case MediaStore.VOLUME_EXTERNAL:
1116 return getPrimaryStorageVolume();
1117 default:
1118 for (StorageVolume vol : getStorageVolumes()) {
1119 if (Objects.equals(vol.getNormalizedUuid(), volumeName)) {
1120 return vol;
1121 }
1122 }
1123 }
1124 throw new IllegalStateException("Unknown volume for " + uri);
1125 }
1126
Jeff Sharkey48877892015-03-18 11:27:19 -07001127 /** {@hide} */
1128 public static @Nullable StorageVolume getStorageVolume(File file, int userId) {
Jeff Sharkey46349872015-07-28 10:49:47 -07001129 return getStorageVolume(getVolumeList(userId, 0), file);
Jeff Sharkey48877892015-03-18 11:27:19 -07001130 }
1131
1132 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +01001133 @UnsupportedAppUsage
Jeff Sharkey48877892015-03-18 11:27:19 -07001134 private static @Nullable StorageVolume getStorageVolume(StorageVolume[] volumes, File file) {
Felipe Lemec250e452016-04-11 18:44:33 -07001135 if (file == null) {
1136 return null;
1137 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001138 try {
Jeff Sharkey983294592015-07-13 10:25:31 -07001139 file = file.getCanonicalFile();
Jeff Sharkey48877892015-03-18 11:27:19 -07001140 } catch (IOException ignored) {
Felipe Lemec250e452016-04-11 18:44:33 -07001141 Slog.d(TAG, "Could not get canonical path for " + file);
Jeff Sharkey983294592015-07-13 10:25:31 -07001142 return null;
Jeff Sharkey48877892015-03-18 11:27:19 -07001143 }
1144 for (StorageVolume volume : volumes) {
Jeff Sharkey983294592015-07-13 10:25:31 -07001145 File volumeFile = volume.getPathFile();
1146 try {
1147 volumeFile = volumeFile.getCanonicalFile();
1148 } catch (IOException ignored) {
1149 continue;
Jeff Sharkey48877892015-03-18 11:27:19 -07001150 }
Jeff Sharkey983294592015-07-13 10:25:31 -07001151 if (FileUtils.contains(volumeFile, file)) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001152 return volume;
1153 }
1154 }
1155 return null;
1156 }
1157
Mike Lockwoodd967f462011-03-24 08:12:30 -07001158 /**
1159 * Gets the state of a volume via its mountpoint.
1160 * @hide
1161 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001162 @Deprecated
Mathew Inwood98e9ad12018-08-30 13:11:50 +01001163 @UnsupportedAppUsage
Jeff Sharkey48877892015-03-18 11:27:19 -07001164 public @NonNull String getVolumeState(String mountPoint) {
1165 final StorageVolume vol = getStorageVolume(new File(mountPoint));
1166 if (vol != null) {
1167 return vol.getState();
1168 } else {
1169 return Environment.MEDIA_UNKNOWN;
Mike Lockwoodd967f462011-03-24 08:12:30 -07001170 }
1171 }
1172
Felipe Leme04a5d402016-02-08 16:44:06 -08001173 /**
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001174 * Return the list of shared/external storage volumes available to the
1175 * current user. This includes both the primary shared storage device and
1176 * any attached external volumes including SD cards and USB drives.
Felipe Leme04a5d402016-02-08 16:44:06 -08001177 *
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001178 * @see Environment#getExternalStorageDirectory()
1179 * @see StorageVolume#createAccessIntent(String)
Felipe Leme04a5d402016-02-08 16:44:06 -08001180 */
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001181 public @NonNull List<StorageVolume> getStorageVolumes() {
1182 final ArrayList<StorageVolume> res = new ArrayList<>();
1183 Collections.addAll(res,
Jeff Sharkeyad357d12018-02-02 13:25:31 -07001184 getVolumeList(mContext.getUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE));
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001185 return res;
1186 }
1187
1188 /**
1189 * Return the primary shared/external storage volume available to the
1190 * current user. This volume is the same storage device returned by
1191 * {@link Environment#getExternalStorageDirectory()} and
1192 * {@link Context#getExternalFilesDir(String)}.
1193 */
1194 public @NonNull StorageVolume getPrimaryStorageVolume() {
Jeff Sharkeyad357d12018-02-02 13:25:31 -07001195 return getVolumeList(mContext.getUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE)[0];
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001196 }
1197
Felipe Leme18202e00b2016-05-12 12:56:28 -07001198 /** {@hide} */
Felipe Leme281389a2016-10-10 17:12:20 -07001199 public static Pair<String, Long> getPrimaryStoragePathAndSize() {
Jeff Sharkey24403ff2017-04-04 15:09:58 -06001200 return Pair.create(null,
hj.seoe82e89ef92017-12-20 09:39:47 +09001201 FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace()
1202 + Environment.getRootDirectory().getTotalSpace()));
Felipe Leme18202e00b2016-05-12 12:56:28 -07001203 }
1204
Felipe Leme281389a2016-10-10 17:12:20 -07001205 /** {@hide} */
1206 public long getPrimaryStorageSize() {
hj.seoe82e89ef92017-12-20 09:39:47 +09001207 return FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace()
1208 + Environment.getRootDirectory().getTotalSpace());
Felipe Leme18202e00b2016-05-12 12:56:28 -07001209 }
1210
Jeff Sharkeyae266462017-11-27 13:32:24 -07001211 /** {@hide} */
1212 public void mkdirs(File file) {
Jeff Sharkeydd02e332018-06-27 14:41:57 -06001213 BlockGuard.getVmPolicy().onPathAccess(file.getAbsolutePath());
Jeff Sharkeyae266462017-11-27 13:32:24 -07001214 try {
1215 mStorageManager.mkdirs(mContext.getOpPackageName(), file.getAbsolutePath());
1216 } catch (RemoteException e) {
1217 throw e.rethrowFromSystemServer();
1218 }
1219 }
1220
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001221 /** @removed */
Jeff Sharkey48877892015-03-18 11:27:19 -07001222 public @NonNull StorageVolume[] getVolumeList() {
Jeff Sharkey46349872015-07-28 10:49:47 -07001223 return getVolumeList(mContext.getUserId(), 0);
Jeff Sharkey48877892015-03-18 11:27:19 -07001224 }
1225
1226 /** {@hide} */
Mathew Inwood98e9ad12018-08-30 13:11:50 +01001227 @UnsupportedAppUsage
Jeff Sharkey46349872015-07-28 10:49:47 -07001228 public static @NonNull StorageVolume[] getVolumeList(int userId, int flags) {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001229 final IStorageManager storageManager = IStorageManager.Stub.asInterface(
Jeff Sharkey48877892015-03-18 11:27:19 -07001230 ServiceManager.getService("mount"));
1231 try {
Svetoslav7395cbf2015-07-15 15:58:01 -07001232 String packageName = ActivityThread.currentOpPackageName();
1233 if (packageName == null) {
1234 // Package name can be null if the activity thread is running but the app
1235 // hasn't bound yet. In this case we fall back to the first package in the
1236 // current UID. This works for runtime permissions as permission state is
1237 // per UID and permission realted app ops are updated for all UID packages.
1238 String[] packageNames = ActivityThread.getPackageManager().getPackagesForUid(
1239 android.os.Process.myUid());
1240 if (packageNames == null || packageNames.length <= 0) {
1241 return new StorageVolume[0];
1242 }
1243 packageName = packageNames[0];
1244 }
Jeff Sharkeycd654482016-01-08 17:42:11 -07001245 final int uid = ActivityThread.getPackageManager().getPackageUid(packageName,
Jeff Sharkeyc5967e92016-01-07 18:50:29 -07001246 PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
Svetoslav7395cbf2015-07-15 15:58:01 -07001247 if (uid <= 0) {
1248 return new StorageVolume[0];
1249 }
Sudheer Shanka2250d562016-11-07 15:41:02 -08001250 return storageManager.getVolumeList(uid, packageName, flags);
Jeff Sharkey48877892015-03-18 11:27:19 -07001251 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001252 throw e.rethrowFromSystemServer();
Mike Lockwoodd967f462011-03-24 08:12:30 -07001253 }
1254 }
Mike Lockwood2f6a3882011-05-09 19:08:06 -07001255
1256 /**
1257 * Returns list of paths for all mountable volumes.
1258 * @hide
1259 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001260 @Deprecated
Mathew Inwood98e9ad12018-08-30 13:11:50 +01001261 @UnsupportedAppUsage
Jeff Sharkey48877892015-03-18 11:27:19 -07001262 public @NonNull String[] getVolumePaths() {
Mike Lockwood2f6a3882011-05-09 19:08:06 -07001263 StorageVolume[] volumes = getVolumeList();
Mike Lockwood2f6a3882011-05-09 19:08:06 -07001264 int count = volumes.length;
1265 String[] paths = new String[count];
1266 for (int i = 0; i < count; i++) {
1267 paths[i] = volumes[i].getPath();
1268 }
1269 return paths;
1270 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001271
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001272 /** @removed */
Jeff Sharkey48877892015-03-18 11:27:19 -07001273 public @NonNull StorageVolume getPrimaryVolume() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001274 return getPrimaryVolume(getVolumeList());
1275 }
1276
1277 /** {@hide} */
Jeff Sharkey48877892015-03-18 11:27:19 -07001278 public static @NonNull StorageVolume getPrimaryVolume(StorageVolume[] volumes) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001279 for (StorageVolume volume : volumes) {
1280 if (volume.isPrimary()) {
1281 return volume;
1282 }
1283 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001284 throw new IllegalStateException("Missing primary storage");
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001285 }
Jeff Sharkeybe722152013-02-15 16:56:38 -08001286
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001287 private static final int DEFAULT_THRESHOLD_PERCENTAGE = 5;
Jeff Sharkey9f2dc052018-01-07 16:47:31 -07001288 private static final long DEFAULT_THRESHOLD_MAX_BYTES = DataUnit.MEBIBYTES.toBytes(500);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001289
1290 private static final int DEFAULT_CACHE_PERCENTAGE = 10;
Jeff Sharkey9f2dc052018-01-07 16:47:31 -07001291 private static final long DEFAULT_CACHE_MAX_BYTES = DataUnit.GIBIBYTES.toBytes(5);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001292
Jeff Sharkey9f2dc052018-01-07 16:47:31 -07001293 private static final long DEFAULT_FULL_THRESHOLD_BYTES = DataUnit.MEBIBYTES.toBytes(1);
Jeff Sharkeybe722152013-02-15 16:56:38 -08001294
1295 /**
Jeff Sharkey742e7902014-08-16 19:09:13 -07001296 * Return the number of available bytes until the given path is considered
1297 * running low on storage.
1298 *
1299 * @hide
1300 */
Mathew Inwood98e9ad12018-08-30 13:11:50 +01001301 @UnsupportedAppUsage
Jeff Sharkey742e7902014-08-16 19:09:13 -07001302 public long getStorageBytesUntilLow(File path) {
1303 return path.getUsableSpace() - getStorageFullBytes(path);
1304 }
1305
1306 /**
Jeff Sharkeybe722152013-02-15 16:56:38 -08001307 * Return the number of available bytes at which the given path is
1308 * considered running low on storage.
1309 *
1310 * @hide
1311 */
Mathew Inwood98e9ad12018-08-30 13:11:50 +01001312 @UnsupportedAppUsage
Jeff Sharkeybe722152013-02-15 16:56:38 -08001313 public long getStorageLowBytes(File path) {
1314 final long lowPercent = Settings.Global.getInt(mResolver,
1315 Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE);
1316 final long lowBytes = (path.getTotalSpace() * lowPercent) / 100;
1317
1318 final long maxLowBytes = Settings.Global.getLong(mResolver,
1319 Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES);
1320
1321 return Math.min(lowBytes, maxLowBytes);
1322 }
1323
1324 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001325 * Return the minimum number of bytes of storage on the device that should
1326 * be reserved for cached data.
1327 *
1328 * @hide
1329 */
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001330 public long getStorageCacheBytes(File path, @AllocateFlags int flags) {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001331 final long cachePercent = Settings.Global.getInt(mResolver,
1332 Settings.Global.SYS_STORAGE_CACHE_PERCENTAGE, DEFAULT_CACHE_PERCENTAGE);
1333 final long cacheBytes = (path.getTotalSpace() * cachePercent) / 100;
1334
1335 final long maxCacheBytes = Settings.Global.getLong(mResolver,
1336 Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES, DEFAULT_CACHE_MAX_BYTES);
1337
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001338 final long result = Math.min(cacheBytes, maxCacheBytes);
1339 if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
1340 return 0;
1341 } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED) != 0) {
1342 return 0;
1343 } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED) != 0) {
1344 return result / 2;
1345 } else {
1346 return result;
1347 }
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001348 }
1349
1350 /**
Jeff Sharkeybe722152013-02-15 16:56:38 -08001351 * Return the number of available bytes at which the given path is
1352 * considered full.
1353 *
1354 * @hide
1355 */
Mathew Inwood98e9ad12018-08-30 13:11:50 +01001356 @UnsupportedAppUsage
Jeff Sharkeybe722152013-02-15 16:56:38 -08001357 public long getStorageFullBytes(File path) {
1358 return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
1359 DEFAULT_FULL_THRESHOLD_BYTES);
1360 }
Paul Lawrencee8fdc542014-05-28 07:14:17 -07001361
Jeff Sharkey50a05452015-04-29 11:24:52 -07001362 /** {@hide} */
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01001363 public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
Paul Crowleybcf48ed2015-04-22 13:36:59 +01001364 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001365 mStorageManager.createUserKey(userId, serialNumber, ephemeral);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01001366 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001367 throw e.rethrowFromSystemServer();
Paul Crowleybcf48ed2015-04-22 13:36:59 +01001368 }
1369 }
1370
1371 /** {@hide} */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001372 public void destroyUserKey(int userId) {
Paul Crowley7ec733f2015-05-19 12:42:00 +01001373 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001374 mStorageManager.destroyUserKey(userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001375 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001376 throw e.rethrowFromSystemServer();
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001377 }
1378 }
1379
1380 /** {@hide} */
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001381 public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001382 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001383 mStorageManager.unlockUserKey(userId, serialNumber, token, secret);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001384 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001385 throw e.rethrowFromSystemServer();
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001386 }
1387 }
1388
1389 /** {@hide} */
1390 public void lockUserKey(int userId) {
1391 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001392 mStorageManager.lockUserKey(userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001393 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001394 throw e.rethrowFromSystemServer();
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001395 }
1396 }
1397
1398 /** {@hide} */
Jeff Sharkey47f71082016-02-01 17:03:54 -07001399 public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001400 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001401 mStorageManager.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001402 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001403 throw e.rethrowFromSystemServer();
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001404 }
1405 }
1406
1407 /** {@hide} */
Jeff Sharkeyfcf1e552016-04-14 20:44:58 -06001408 public void destroyUserStorage(String volumeUuid, int userId, int flags) {
1409 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001410 mStorageManager.destroyUserStorage(volumeUuid, userId, flags);
Jeff Sharkeyfcf1e552016-04-14 20:44:58 -06001411 } catch (RemoteException e) {
1412 throw e.rethrowFromSystemServer();
1413 }
1414 }
1415
1416 /** {@hide} */
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001417 public static boolean isUserKeyUnlocked(int userId) {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001418 if (sStorageManager == null) {
1419 sStorageManager = IStorageManager.Stub
Jeff Sharkey4815ed42016-05-26 09:31:04 -06001420 .asInterface(ServiceManager.getService("mount"));
1421 }
Sudheer Shanka2250d562016-11-07 15:41:02 -08001422 if (sStorageManager == null) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001423 Slog.w(TAG, "Early during boot, assuming locked");
1424 return false;
1425 }
1426 final long token = Binder.clearCallingIdentity();
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001427 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001428 return sStorageManager.isUserKeyUnlocked(userId);
Paul Crowley7ec733f2015-05-19 12:42:00 +01001429 } catch (RemoteException e) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001430 throw e.rethrowAsRuntimeException();
1431 } finally {
1432 Binder.restoreCallingIdentity(token);
Paul Crowley7ec733f2015-05-19 12:42:00 +01001433 }
1434 }
1435
Jeff Sharkeycf3f0a12016-03-17 19:57:58 -06001436 /**
Jeff Sharkeyf82c2f02016-04-12 15:19:10 -06001437 * Return if data stored at or under the given path will be encrypted while
1438 * at rest. This can help apps avoid the overhead of double-encrypting data.
Jeff Sharkeycf3f0a12016-03-17 19:57:58 -06001439 */
1440 public boolean isEncrypted(File file) {
1441 if (FileUtils.contains(Environment.getDataDirectory(), file)) {
1442 return isEncrypted();
1443 } else if (FileUtils.contains(Environment.getExpandDirectory(), file)) {
1444 return true;
1445 }
1446 // TODO: extend to support shared storage
1447 return false;
1448 }
1449
Paul Lawrence20be5d62016-02-26 13:51:17 -08001450 /** {@hide}
1451 * Is this device encryptable or already encrypted?
1452 * @return true for encryptable or encrypted
1453 * false not encrypted and not encryptable
1454 */
1455 public static boolean isEncryptable() {
John Reckaa67f682016-09-20 14:24:21 -07001456 return RoSystemProperties.CRYPTO_ENCRYPTABLE;
Paul Lawrence20be5d62016-02-26 13:51:17 -08001457 }
1458
1459 /** {@hide}
1460 * Is this device already encrypted?
1461 * @return true for encrypted. (Implies isEncryptable() == true)
1462 * false not encrypted
1463 */
1464 public static boolean isEncrypted() {
John Reckaa67f682016-09-20 14:24:21 -07001465 return RoSystemProperties.CRYPTO_ENCRYPTED;
Paul Lawrence20be5d62016-02-26 13:51:17 -08001466 }
1467
1468 /** {@hide}
1469 * Is this device file encrypted?
1470 * @return true for file encrypted. (Implies isEncrypted() == true)
1471 * false not encrypted or block encrypted
1472 */
Mathew Inwood98e9ad12018-08-30 13:11:50 +01001473 @UnsupportedAppUsage
Paul Lawrence20be5d62016-02-26 13:51:17 -08001474 public static boolean isFileEncryptedNativeOnly() {
1475 if (!isEncrypted()) {
1476 return false;
1477 }
John Reckaa67f682016-09-20 14:24:21 -07001478 return RoSystemProperties.CRYPTO_FILE_ENCRYPTED;
Paul Lawrence20be5d62016-02-26 13:51:17 -08001479 }
1480
1481 /** {@hide}
1482 * Is this device block encrypted?
1483 * @return true for block encrypted. (Implies isEncrypted() == true)
1484 * false not encrypted or file encrypted
1485 */
1486 public static boolean isBlockEncrypted() {
1487 if (!isEncrypted()) {
1488 return false;
1489 }
John Reckaa67f682016-09-20 14:24:21 -07001490 return RoSystemProperties.CRYPTO_BLOCK_ENCRYPTED;
Paul Lawrence20be5d62016-02-26 13:51:17 -08001491 }
1492
1493 /** {@hide}
1494 * Is this device block encrypted with credentials?
1495 * @return true for crediential block encrypted.
1496 * (Implies isBlockEncrypted() == true)
1497 * false not encrypted, file encrypted or default block encrypted
1498 */
1499 public static boolean isNonDefaultBlockEncrypted() {
1500 if (!isBlockEncrypted()) {
1501 return false;
1502 }
1503
1504 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001505 IStorageManager storageManager = IStorageManager.Stub.asInterface(
Paul Lawrence20be5d62016-02-26 13:51:17 -08001506 ServiceManager.getService("mount"));
Sudheer Shanka2250d562016-11-07 15:41:02 -08001507 return storageManager.getPasswordType() != CRYPT_TYPE_DEFAULT;
Paul Lawrence20be5d62016-02-26 13:51:17 -08001508 } catch (RemoteException e) {
1509 Log.e(TAG, "Error getting encryption type");
1510 return false;
1511 }
1512 }
1513
1514 /** {@hide}
1515 * Is this device in the process of being block encrypted?
1516 * @return true for encrypting.
1517 * false otherwise
1518 * Whether device isEncrypted at this point is undefined
1519 * Note that only system services and CryptKeeper will ever see this return
1520 * true - no app will ever be launched in this state.
1521 * Also note that this state will not change without a teardown of the
1522 * framework, so no service needs to check for changes during their lifespan
1523 */
1524 public static boolean isBlockEncrypting() {
Inseob Kimc1246e62018-11-08 13:13:54 +09001525 final String state = VoldProperties.encrypt_progress().orElse("");
Paul Lawrence20be5d62016-02-26 13:51:17 -08001526 return !"".equalsIgnoreCase(state);
1527 }
1528
1529 /** {@hide}
1530 * Is this device non default block encrypted and in the process of
1531 * prompting for credentials?
1532 * @return true for prompting for credentials.
1533 * (Implies isNonDefaultBlockEncrypted() == true)
1534 * false otherwise
1535 * Note that only system services and CryptKeeper will ever see this return
1536 * true - no app will ever be launched in this state.
1537 * Also note that this state will not change without a teardown of the
1538 * framework, so no service needs to check for changes during their lifespan
1539 */
1540 public static boolean inCryptKeeperBounce() {
Inseob Kimc1246e62018-11-08 13:13:54 +09001541 final String status = VoldProperties.decrypt().orElse("");
Paul Lawrence20be5d62016-02-26 13:51:17 -08001542 return "trigger_restart_min_framework".equals(status);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001543 }
1544
1545 /** {@hide} */
Paul Lawrence20be5d62016-02-26 13:51:17 -08001546 public static boolean isFileEncryptedEmulatedOnly() {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001547 return SystemProperties.getBoolean(StorageManager.PROP_EMULATE_FBE, false);
Clara Bayarri965da392015-10-28 17:53:53 +00001548 }
1549
Paul Lawrence20be5d62016-02-26 13:51:17 -08001550 /** {@hide}
1551 * Is this device running in a file encrypted mode, either native or emulated?
1552 * @return true for file encrypted, false otherwise
1553 */
1554 public static boolean isFileEncryptedNativeOrEmulated() {
1555 return isFileEncryptedNativeOnly()
1556 || isFileEncryptedEmulatedOnly();
1557 }
1558
Clara Bayarri965da392015-10-28 17:53:53 +00001559 /** {@hide} */
Jeff Sharkey8eb783b2018-01-04 16:46:48 -07001560 public static boolean hasAdoptable() {
1561 return SystemProperties.getBoolean(PROP_HAS_ADOPTABLE, false);
1562 }
1563
Jeff Sharkeyb91eaa52019-02-19 11:09:13 -07001564 /**
1565 * Return if the currently booted device has the "isolated storage" feature
1566 * flag enabled. This will eventually be fully enabled in the final
1567 * {@link android.os.Build.VERSION_CODES#Q} release.
1568 *
1569 * @hide
1570 */
Jeff Sharkeya1767a292019-01-05 12:59:04 -07001571 @SystemApi
Jeff Sharkey10ec9d82018-11-28 14:52:45 -07001572 @TestApi
1573 public static boolean hasIsolatedStorage() {
Jeff Sharkey342b4bf2018-12-18 11:12:40 -07001574 // Prefer to use snapshot for current boot when available
1575 return SystemProperties.getBoolean(PROP_ISOLATED_STORAGE_SNAPSHOT,
Jeff Sharkey06376802019-02-11 12:20:02 -07001576 SystemProperties.getBoolean(PROP_ISOLATED_STORAGE, true));
Jeff Sharkey10ec9d82018-11-28 14:52:45 -07001577 }
1578
Jeff Sharkey70eb34a2018-09-13 11:57:03 -06001579 /**
1580 * @deprecated disabled now that FUSE has been replaced by sdcardfs
1581 * @hide
1582 */
1583 @Deprecated
Jeff Sharkey50a05452015-04-29 11:24:52 -07001584 public static File maybeTranslateEmulatedPathToInternal(File path) {
Jeff Sharkey2063e4f2017-06-06 16:03:24 -06001585 // Disabled now that FUSE has been replaced by sdcardfs
Jeff Sharkey50a05452015-04-29 11:24:52 -07001586 return path;
1587 }
1588
Jeff Sharkey5790af02018-08-13 17:42:54 -06001589 /**
1590 * Translate given shared storage path from a path in an app sandbox
1591 * namespace to a path in the system namespace.
1592 *
1593 * @hide
1594 */
Sudheer Shanka87915d62018-11-06 10:57:35 -08001595 public File translateAppToSystem(File file, int pid, int uid) {
Jeff Sharkeyd2b64d72018-10-19 15:40:03 -06001596 // We can only translate absolute paths
1597 if (!file.isAbsolute()) return file;
1598
Jeff Sharkey5790af02018-08-13 17:42:54 -06001599 try {
1600 return new File(mStorageManager.translateAppToSystem(file.getAbsolutePath(),
Sudheer Shanka87915d62018-11-06 10:57:35 -08001601 pid, uid));
Jeff Sharkey5790af02018-08-13 17:42:54 -06001602 } catch (RemoteException e) {
1603 throw e.rethrowFromSystemServer();
1604 }
1605 }
1606
1607 /**
1608 * Translate given shared storage path from a path in the system namespace
1609 * to a path in an app sandbox namespace.
1610 *
1611 * @hide
1612 */
Sudheer Shanka87915d62018-11-06 10:57:35 -08001613 public File translateSystemToApp(File file, int pid, int uid) {
Jeff Sharkeyd2b64d72018-10-19 15:40:03 -06001614 // We can only translate absolute paths
1615 if (!file.isAbsolute()) return file;
1616
Jeff Sharkey5790af02018-08-13 17:42:54 -06001617 try {
1618 return new File(mStorageManager.translateSystemToApp(file.getAbsolutePath(),
Sudheer Shanka87915d62018-11-06 10:57:35 -08001619 pid, uid));
Jeff Sharkey5790af02018-08-13 17:42:54 -06001620 } catch (RemoteException e) {
1621 throw e.rethrowFromSystemServer();
1622 }
1623 }
1624
Daichi Hirono9e8d9e22015-11-13 14:37:00 +09001625 /** {@hide} */
Daichi Hirono9fb00182016-11-08 14:12:17 +09001626 @VisibleForTesting
1627 public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
Daichi Hirono812c95d2017-02-08 16:20:20 +09001628 int mode, ProxyFileDescriptorCallback callback, Handler handler, ThreadFactory factory)
Daichi Hirono9fb00182016-11-08 14:12:17 +09001629 throws IOException {
Daichi Hirono2443a092017-04-28 14:53:19 +09001630 Preconditions.checkNotNull(callback);
Daichi Hironod61817e2017-02-13 10:37:11 +09001631 MetricsLogger.count(mContext, "storage_open_proxy_file_descriptor", 1);
Daichi Hirono9fb00182016-11-08 14:12:17 +09001632 // Retry is needed because the mount point mFuseAppLoop is using may be unmounted before
1633 // invoking StorageManagerService#openProxyFileDescriptor. In this case, we need to re-mount
1634 // the bridge by calling mountProxyFileDescriptorBridge.
Daichi Hirono812c95d2017-02-08 16:20:20 +09001635 while (true) {
Daichi Hirono9fb00182016-11-08 14:12:17 +09001636 try {
1637 synchronized (mFuseAppLoopLock) {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001638 boolean newlyCreated = false;
Daichi Hirono9fb00182016-11-08 14:12:17 +09001639 if (mFuseAppLoop == null) {
1640 final AppFuseMount mount = mStorageManager.mountProxyFileDescriptorBridge();
1641 if (mount == null) {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001642 throw new IOException("Failed to mount proxy bridge");
Daichi Hirono9fb00182016-11-08 14:12:17 +09001643 }
Daichi Hirono812c95d2017-02-08 16:20:20 +09001644 mFuseAppLoop = new FuseAppLoop(mount.mountPointId, mount.fd, factory);
1645 newlyCreated = true;
Daichi Hirono9fb00182016-11-08 14:12:17 +09001646 }
Daichi Hirono812c95d2017-02-08 16:20:20 +09001647 if (handler == null) {
1648 handler = new Handler(Looper.getMainLooper());
1649 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09001650 try {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001651 final int fileId = mFuseAppLoop.registerCallback(callback, handler);
1652 final ParcelFileDescriptor pfd = mStorageManager.openProxyFileDescriptor(
1653 mFuseAppLoop.getMountPointId(), fileId, mode);
1654 if (pfd == null) {
1655 mFuseAppLoop.unregisterCallback(fileId);
1656 throw new FuseUnavailableMountException(
1657 mFuseAppLoop.getMountPointId());
Daichi Hirono9fb00182016-11-08 14:12:17 +09001658 }
Daichi Hirono812c95d2017-02-08 16:20:20 +09001659 return pfd;
1660 } catch (FuseUnavailableMountException exception) {
1661 // The bridge is being unmounted. Tried to recreate it unless the bridge was
1662 // just created.
1663 if (newlyCreated) {
1664 throw new IOException(exception);
1665 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09001666 mFuseAppLoop = null;
1667 continue;
1668 }
1669 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09001670 } catch (RemoteException e) {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001671 // Cannot recover from remote exception.
1672 throw new IOException(e);
Daichi Hirono9fb00182016-11-08 14:12:17 +09001673 }
1674 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09001675 }
1676
Daichi Hirono2443a092017-04-28 14:53:19 +09001677 /** {@hide} */
Daichi Hirono9fb00182016-11-08 14:12:17 +09001678 public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
1679 int mode, ProxyFileDescriptorCallback callback)
1680 throws IOException {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001681 return openProxyFileDescriptor(mode, callback, null, null);
Daichi Hirono9fb00182016-11-08 14:12:17 +09001682 }
1683
Daichi Hirono812c95d2017-02-08 16:20:20 +09001684 /**
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001685 * Opens a seekable {@link ParcelFileDescriptor} that proxies all low-level
1686 * I/O requests back to the given {@link ProxyFileDescriptorCallback}.
1687 * <p>
1688 * This can be useful when you want to provide quick access to a large file
1689 * that isn't backed by a real file on disk, such as a file on a network
1690 * share, cloud storage service, etc. As an example, you could respond to a
1691 * {@link ContentResolver#openFileDescriptor(android.net.Uri, String)}
1692 * request by returning a {@link ParcelFileDescriptor} created with this
1693 * method, and then stream the content on-demand as requested.
1694 * <p>
1695 * Another useful example might be where you have an encrypted file that
1696 * you're willing to decrypt on-demand, but where you want to avoid
1697 * persisting the cleartext version.
Daichi Hirono812c95d2017-02-08 16:20:20 +09001698 *
1699 * @param mode The desired access mode, must be one of
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001700 * {@link ParcelFileDescriptor#MODE_READ_ONLY},
1701 * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or
1702 * {@link ParcelFileDescriptor#MODE_READ_WRITE}
1703 * @param callback Callback to process file operation requests issued on
1704 * returned file descriptor.
Daichi Hirono812c95d2017-02-08 16:20:20 +09001705 * @param handler Handler that invokes callback methods.
1706 * @return Seekable ParcelFileDescriptor.
1707 * @throws IOException
1708 */
1709 public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
1710 int mode, ProxyFileDescriptorCallback callback, Handler handler)
1711 throws IOException {
Daichi Hirono2443a092017-04-28 14:53:19 +09001712 Preconditions.checkNotNull(handler);
Daichi Hirono812c95d2017-02-08 16:20:20 +09001713 return openProxyFileDescriptor(mode, callback, handler, null);
1714 }
1715
Daichi Hirono9fb00182016-11-08 14:12:17 +09001716 /** {@hide} */
1717 @VisibleForTesting
1718 public int getProxyFileDescriptorMountPointId() {
1719 synchronized (mFuseAppLoopLock) {
1720 return mFuseAppLoop != null ? mFuseAppLoop.getMountPointId() : -1;
1721 }
1722 }
1723
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001724 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001725 * Return quota size in bytes for all cached data belonging to the calling
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001726 * app on the given storage volume.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001727 * <p>
1728 * If your app goes above this quota, your cached files will be some of the
1729 * first to be deleted when additional disk space is needed. Conversely, if
1730 * your app stays under this quota, your cached files will be some of the
1731 * last to be deleted when additional disk space is needed.
1732 * <p>
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001733 * This quota will change over time depending on how frequently the user
Jeff Sharkey60a82cd2017-04-18 18:19:16 -06001734 * interacts with your app, and depending on how much system-wide disk space
1735 * is used.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001736 * <p class="note">
1737 * Note: if your app uses the {@code android:sharedUserId} manifest feature,
1738 * then cached data for all packages in your shared UID is tracked together
1739 * as a single unit.
1740 * </p>
1741 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001742 * @param storageUuid the UUID of the storage volume that you're interested
1743 * in. The UUID for a specific path can be obtained using
1744 * {@link #getUuidForPath(File)}.
1745 * @throws IOException when the storage device isn't present, or when it
1746 * doesn't support cache quotas.
1747 * @see #getCacheSizeBytes(UUID)
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001748 */
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001749 @WorkerThread
1750 public @BytesLong long getCacheQuotaBytes(@NonNull UUID storageUuid) throws IOException {
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001751 try {
1752 final ApplicationInfo app = mContext.getApplicationInfo();
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001753 return mStorageManager.getCacheQuotaBytes(convert(storageUuid), app.uid);
1754 } catch (ParcelableException e) {
1755 e.maybeRethrow(IOException.class);
1756 throw new RuntimeException(e);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001757 } catch (RemoteException e) {
1758 throw e.rethrowFromSystemServer();
1759 }
1760 }
1761
1762 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001763 * Return total size in bytes of all cached data belonging to the calling
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001764 * app on the given storage volume.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001765 * <p>
1766 * Cached data tracked by this method always includes
1767 * {@link Context#getCacheDir()} and {@link Context#getCodeCacheDir()}, and
1768 * it also includes {@link Context#getExternalCacheDir()} if the primary
1769 * shared/external storage is hosted on the same storage device as your
1770 * private data.
1771 * <p class="note">
1772 * Note: if your app uses the {@code android:sharedUserId} manifest feature,
1773 * then cached data for all packages in your shared UID is tracked together
1774 * as a single unit.
1775 * </p>
1776 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001777 * @param storageUuid the UUID of the storage volume that you're interested
1778 * in. The UUID for a specific path can be obtained using
1779 * {@link #getUuidForPath(File)}.
1780 * @throws IOException when the storage device isn't present, or when it
1781 * doesn't support cache quotas.
1782 * @see #getCacheQuotaBytes(UUID)
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001783 */
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001784 @WorkerThread
1785 public @BytesLong long getCacheSizeBytes(@NonNull UUID storageUuid) throws IOException {
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001786 try {
1787 final ApplicationInfo app = mContext.getApplicationInfo();
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001788 return mStorageManager.getCacheSizeBytes(convert(storageUuid), app.uid);
1789 } catch (ParcelableException e) {
1790 e.maybeRethrow(IOException.class);
1791 throw new RuntimeException(e);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001792 } catch (RemoteException e) {
1793 throw e.rethrowFromSystemServer();
1794 }
1795 }
1796
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001797 /**
1798 * Flag indicating that a disk space allocation request should operate in an
1799 * aggressive mode. This flag should only be rarely used in situations that
1800 * are critical to system health or security.
1801 * <p>
1802 * When set, the system is more aggressive about the data that it considers
1803 * for possible deletion when allocating disk space.
1804 * <p class="note">
1805 * Note: your app must hold the
1806 * {@link android.Manifest.permission#ALLOCATE_AGGRESSIVE} permission for
1807 * this flag to take effect.
1808 * </p>
1809 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001810 * @see #getAllocatableBytes(UUID, int)
1811 * @see #allocateBytes(UUID, long, int)
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001812 * @see #allocateBytes(FileDescriptor, long, int)
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001813 * @hide
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001814 */
1815 @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE)
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001816 @SystemApi
Jeff Sharkeyddff8072017-05-26 13:10:46 -06001817 public static final int FLAG_ALLOCATE_AGGRESSIVE = 1 << 0;
1818
1819 /**
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001820 * Flag indicating that a disk space allocation request should be allowed to
1821 * clear up to all reserved disk space.
Jeff Sharkeyddff8072017-05-26 13:10:46 -06001822 *
1823 * @hide
1824 */
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001825 public static final int FLAG_ALLOCATE_DEFY_ALL_RESERVED = 1 << 1;
1826
1827 /**
1828 * Flag indicating that a disk space allocation request should be allowed to
1829 * clear up to half of all reserved disk space.
1830 *
1831 * @hide
1832 */
1833 public static final int FLAG_ALLOCATE_DEFY_HALF_RESERVED = 1 << 2;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001834
1835 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -07001836 @IntDef(flag = true, prefix = { "FLAG_ALLOCATE_" }, value = {
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001837 FLAG_ALLOCATE_AGGRESSIVE,
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001838 FLAG_ALLOCATE_DEFY_ALL_RESERVED,
1839 FLAG_ALLOCATE_DEFY_HALF_RESERVED,
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001840 })
1841 @Retention(RetentionPolicy.SOURCE)
1842 public @interface AllocateFlags {}
1843
1844 /**
1845 * Return the maximum number of new bytes that your app can allocate for
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001846 * itself on the given storage volume. This value is typically larger than
1847 * {@link File#getUsableSpace()}, since the system may be willing to delete
1848 * cached files to satisfy an allocation request. You can then allocate
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001849 * space for yourself using {@link #allocateBytes(UUID, long)} or
1850 * {@link #allocateBytes(FileDescriptor, long)}.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001851 * <p>
1852 * This method is best used as a pre-flight check, such as deciding if there
1853 * is enough space to store an entire music album before you allocate space
1854 * for each audio file in the album. Attempts to allocate disk space beyond
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001855 * the returned value will fail.
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001856 * <p>
1857 * If the returned value is not large enough for the data you'd like to
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001858 * persist, you can launch {@link #ACTION_MANAGE_STORAGE} with the
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001859 * {@link #EXTRA_UUID} and {@link #EXTRA_REQUESTED_BYTES} options to help
1860 * involve the user in freeing up disk space.
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001861 * <p>
1862 * If you're progressively allocating an unbounded amount of storage space
1863 * (such as when recording a video) you should avoid calling this method
1864 * more than once every 30 seconds.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001865 * <p class="note">
1866 * Note: if your app uses the {@code android:sharedUserId} manifest feature,
1867 * then allocatable space for all packages in your shared UID is tracked
1868 * together as a single unit.
1869 * </p>
1870 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001871 * @param storageUuid the UUID of the storage volume where you're
1872 * considering allocating disk space, since allocatable space can
1873 * vary widely depending on the underlying storage device. The
1874 * UUID for a specific path can be obtained using
1875 * {@link #getUuidForPath(File)}.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001876 * @return the maximum number of new bytes that the calling app can allocate
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001877 * using {@link #allocateBytes(UUID, long)} or
1878 * {@link #allocateBytes(FileDescriptor, long)}.
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001879 * @throws IOException when the storage device isn't present, or when it
1880 * doesn't support allocating space.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001881 */
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001882 @WorkerThread
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001883 public @BytesLong long getAllocatableBytes(@NonNull UUID storageUuid)
1884 throws IOException {
1885 return getAllocatableBytes(storageUuid, 0);
1886 }
1887
1888 /** @hide */
1889 @SystemApi
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001890 @WorkerThread
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -06001891 @SuppressLint("Doclava125")
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001892 public long getAllocatableBytes(@NonNull UUID storageUuid,
1893 @RequiresPermission @AllocateFlags int flags) throws IOException {
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001894 try {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001895 return mStorageManager.getAllocatableBytes(convert(storageUuid), flags,
1896 mContext.getOpPackageName());
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001897 } catch (ParcelableException e) {
1898 e.maybeRethrow(IOException.class);
1899 throw new RuntimeException(e);
1900 } catch (RemoteException e) {
1901 throw e.rethrowFromSystemServer();
1902 }
1903 }
1904
1905 /**
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001906 * Allocate the requested number of bytes for your application to use on the
1907 * given storage volume. This will cause the system to delete any cached
1908 * files necessary to satisfy your request.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001909 * <p>
1910 * Attempts to allocate disk space beyond the value returned by
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001911 * {@link #getAllocatableBytes(UUID)} will fail.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001912 * <p>
1913 * Since multiple apps can be running simultaneously, this method may be
1914 * subject to race conditions. If possible, consider using
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001915 * {@link #allocateBytes(FileDescriptor, long)} which will guarantee
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001916 * that bytes are allocated to an opened file.
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001917 * <p>
1918 * If you're progressively allocating an unbounded amount of storage space
1919 * (such as when recording a video) you should avoid calling this method
1920 * more than once every 60 seconds.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001921 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001922 * @param storageUuid the UUID of the storage volume where you'd like to
1923 * allocate disk space. The UUID for a specific path can be
1924 * obtained using {@link #getUuidForPath(File)}.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001925 * @param bytes the number of bytes to allocate.
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001926 * @throws IOException when the storage device isn't present, or when it
1927 * doesn't support allocating space, or if the device had
1928 * trouble allocating the requested space.
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001929 * @see #getAllocatableBytes(UUID)
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001930 */
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001931 @WorkerThread
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001932 public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes)
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001933 throws IOException {
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001934 allocateBytes(storageUuid, bytes, 0);
1935 }
1936
1937 /** @hide */
1938 @SystemApi
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001939 @WorkerThread
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -06001940 @SuppressLint("Doclava125")
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001941 public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes,
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001942 @RequiresPermission @AllocateFlags int flags) throws IOException {
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001943 try {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001944 mStorageManager.allocateBytes(convert(storageUuid), bytes, flags,
1945 mContext.getOpPackageName());
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001946 } catch (ParcelableException e) {
1947 e.maybeRethrow(IOException.class);
1948 } catch (RemoteException e) {
1949 throw e.rethrowFromSystemServer();
1950 }
1951 }
1952
1953 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001954 * Allocate the requested number of bytes for your application to use in the
1955 * given open file. This will cause the system to delete any cached files
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001956 * necessary to satisfy your request.
1957 * <p>
1958 * Attempts to allocate disk space beyond the value returned by
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001959 * {@link #getAllocatableBytes(UUID)} will fail.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001960 * <p>
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001961 * This method guarantees that bytes have been allocated to the opened file,
1962 * otherwise it will throw if fast allocation is not possible. Fast
1963 * allocation is typically only supported in private app data directories,
1964 * and on shared/external storage devices which are emulated.
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001965 * <p>
1966 * If you're progressively allocating an unbounded amount of storage space
1967 * (such as when recording a video) you should avoid calling this method
1968 * more than once every 60 seconds.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001969 *
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001970 * @param fd the open file that you'd like to allocate disk space for.
1971 * @param bytes the number of bytes to allocate. This is the desired final
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001972 * size of the open file. If the open file is smaller than this
1973 * requested size, it will be extended without modifying any
1974 * existing contents. If the open file is larger than this
1975 * requested size, it will be truncated.
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001976 * @throws IOException when the storage device isn't present, or when it
1977 * doesn't support allocating space, or if the device had
1978 * trouble allocating the requested space.
Jeff Sharkey4233f032017-07-15 12:58:38 -06001979 * @see #isAllocationSupported(FileDescriptor)
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001980 * @see Environment#isExternalStorageEmulated(File)
1981 */
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001982 @WorkerThread
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001983 public void allocateBytes(FileDescriptor fd, @BytesLong long bytes) throws IOException {
1984 allocateBytes(fd, bytes, 0);
1985 }
1986
1987 /** @hide */
1988 @SystemApi
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001989 @WorkerThread
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -06001990 @SuppressLint("Doclava125")
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001991 public void allocateBytes(FileDescriptor fd, @BytesLong long bytes,
1992 @RequiresPermission @AllocateFlags int flags) throws IOException {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001993 final File file = ParcelFileDescriptor.getFile(fd);
Jeff Sharkey4233f032017-07-15 12:58:38 -06001994 final UUID uuid = getUuidForPath(file);
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001995 for (int i = 0; i < 3; i++) {
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001996 try {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001997 final long haveBytes = Os.fstat(fd).st_blocks * 512;
1998 final long needBytes = bytes - haveBytes;
1999
2000 if (needBytes > 0) {
Jeff Sharkey4233f032017-07-15 12:58:38 -06002001 allocateBytes(uuid, needBytes, flags);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07002002 }
2003
Jeff Sharkey4233f032017-07-15 12:58:38 -06002004 try {
2005 Os.posix_fallocate(fd, 0, bytes);
2006 return;
2007 } catch (ErrnoException e) {
2008 if (e.errno == OsConstants.ENOSYS || e.errno == OsConstants.ENOTSUP) {
2009 Log.w(TAG, "fallocate() not supported; falling back to ftruncate()");
2010 Os.ftruncate(fd, bytes);
2011 return;
2012 } else {
2013 throw e;
2014 }
2015 }
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07002016 } catch (ErrnoException e) {
2017 if (e.errno == OsConstants.ENOSPC) {
2018 Log.w(TAG, "Odd, not enough space; let's try again?");
2019 continue;
2020 }
2021 throw e.rethrowAsIOException();
2022 }
2023 }
2024 throw new IOException(
2025 "Well this is embarassing; we can't allocate " + bytes + " for " + file);
2026 }
2027
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06002028 private static final String XATTR_CACHE_GROUP = "user.cache_group";
Jeff Sharkey458428e2017-02-22 11:47:15 -07002029 private static final String XATTR_CACHE_TOMBSTONE = "user.cache_tombstone";
Jeff Sharkey9bed0702017-01-23 20:37:05 -07002030
2031 /** {@hide} */
2032 private static void setCacheBehavior(File path, String name, boolean enabled)
2033 throws IOException {
2034 if (!path.isDirectory()) {
2035 throw new IOException("Cache behavior can only be set on directories");
2036 }
2037 if (enabled) {
2038 try {
2039 Os.setxattr(path.getAbsolutePath(), name,
2040 "1".getBytes(StandardCharsets.UTF_8), 0);
2041 } catch (ErrnoException e) {
2042 throw e.rethrowAsIOException();
2043 }
2044 } else {
2045 try {
2046 Os.removexattr(path.getAbsolutePath(), name);
2047 } catch (ErrnoException e) {
2048 if (e.errno != OsConstants.ENODATA) {
2049 throw e.rethrowAsIOException();
2050 }
2051 }
2052 }
2053 }
2054
2055 /** {@hide} */
2056 private static boolean isCacheBehavior(File path, String name) throws IOException {
2057 try {
2058 Os.getxattr(path.getAbsolutePath(), name);
2059 return true;
2060 } catch (ErrnoException e) {
2061 if (e.errno != OsConstants.ENODATA) {
2062 throw e.rethrowAsIOException();
2063 } else {
2064 return false;
2065 }
2066 }
2067 }
2068
2069 /**
2070 * Enable or disable special cache behavior that treats this directory and
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06002071 * its contents as an entire group.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07002072 * <p>
2073 * When enabled and this directory is considered for automatic deletion by
2074 * the OS, all contained files will either be deleted together, or not at
2075 * all. This is useful when you have a directory that contains several
2076 * related metadata files that depend on each other, such as movie file and
2077 * a subtitle file.
2078 * <p>
2079 * When enabled, the <em>newest</em> {@link File#lastModified()} value of
2080 * any contained files is considered the modified time of the entire
2081 * directory.
2082 * <p>
2083 * This behavior can only be set on a directory, and it applies recursively
2084 * to all contained files and directories.
2085 */
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06002086 public void setCacheBehaviorGroup(File path, boolean group) throws IOException {
2087 setCacheBehavior(path, XATTR_CACHE_GROUP, group);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07002088 }
2089
2090 /**
2091 * Read the current value set by
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06002092 * {@link #setCacheBehaviorGroup(File, boolean)}.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07002093 */
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06002094 public boolean isCacheBehaviorGroup(File path) throws IOException {
2095 return isCacheBehavior(path, XATTR_CACHE_GROUP);
2096 }
2097
Jeff Sharkey9bed0702017-01-23 20:37:05 -07002098 /**
2099 * Enable or disable special cache behavior that leaves deleted cache files
2100 * intact as tombstones.
2101 * <p>
2102 * When enabled and a file contained in this directory is automatically
2103 * deleted by the OS, the file will be truncated to have a length of 0 bytes
2104 * instead of being fully deleted. This is useful if you need to distinguish
2105 * between a file that was deleted versus one that never existed.
2106 * <p>
2107 * This behavior can only be set on a directory, and it applies recursively
2108 * to all contained files and directories.
2109 * <p class="note">
2110 * Note: this behavior is ignored completely if the user explicitly requests
2111 * that all cached data be cleared.
2112 * </p>
2113 */
2114 public void setCacheBehaviorTombstone(File path, boolean tombstone) throws IOException {
Jeff Sharkey458428e2017-02-22 11:47:15 -07002115 setCacheBehavior(path, XATTR_CACHE_TOMBSTONE, tombstone);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07002116 }
2117
2118 /**
2119 * Read the current value set by
2120 * {@link #setCacheBehaviorTombstone(File, boolean)}.
2121 */
2122 public boolean isCacheBehaviorTombstone(File path) throws IOException {
Jeff Sharkey458428e2017-02-22 11:47:15 -07002123 return isCacheBehavior(path, XATTR_CACHE_TOMBSTONE);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07002124 }
2125
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06002126 /** {@hide} */
2127 public static UUID convert(String uuid) {
2128 if (Objects.equals(uuid, UUID_PRIVATE_INTERNAL)) {
2129 return UUID_DEFAULT;
2130 } else if (Objects.equals(uuid, UUID_PRIMARY_PHYSICAL)) {
2131 return UUID_PRIMARY_PHYSICAL_;
2132 } else if (Objects.equals(uuid, UUID_SYSTEM)) {
2133 return UUID_SYSTEM_;
2134 } else {
2135 return UUID.fromString(uuid);
2136 }
2137 }
2138
2139 /** {@hide} */
2140 public static String convert(UUID storageUuid) {
2141 if (UUID_DEFAULT.equals(storageUuid)) {
2142 return UUID_PRIVATE_INTERNAL;
2143 } else if (UUID_PRIMARY_PHYSICAL_.equals(storageUuid)) {
2144 return UUID_PRIMARY_PHYSICAL;
2145 } else if (UUID_SYSTEM_.equals(storageUuid)) {
2146 return UUID_SYSTEM;
2147 } else {
2148 return storageUuid.toString();
2149 }
2150 }
2151
Daichi Hirono9fb00182016-11-08 14:12:17 +09002152 private final Object mFuseAppLoopLock = new Object();
2153
2154 @GuardedBy("mFuseAppLoopLock")
2155 private @Nullable FuseAppLoop mFuseAppLoop = null;
2156
Paul Lawrencee8fdc542014-05-28 07:14:17 -07002157 /// Consts to match the password types in cryptfs.h
2158 /** @hide */
Mathew Inwood98e9ad12018-08-30 13:11:50 +01002159 @UnsupportedAppUsage
Jeff Sharkey43e12112017-09-12 16:31:45 -06002160 public static final int CRYPT_TYPE_PASSWORD = IVold.PASSWORD_TYPE_PASSWORD;
Paul Lawrencee8fdc542014-05-28 07:14:17 -07002161 /** @hide */
Mathew Inwood98e9ad12018-08-30 13:11:50 +01002162 @UnsupportedAppUsage
Jeff Sharkey43e12112017-09-12 16:31:45 -06002163 public static final int CRYPT_TYPE_DEFAULT = IVold.PASSWORD_TYPE_DEFAULT;
Paul Lawrencee8fdc542014-05-28 07:14:17 -07002164 /** @hide */
Jeff Sharkey43e12112017-09-12 16:31:45 -06002165 public static final int CRYPT_TYPE_PATTERN = IVold.PASSWORD_TYPE_PATTERN;
Paul Lawrencee8fdc542014-05-28 07:14:17 -07002166 /** @hide */
Jeff Sharkey43e12112017-09-12 16:31:45 -06002167 public static final int CRYPT_TYPE_PIN = IVold.PASSWORD_TYPE_PIN;
Elliott Hughesf839b4f2014-09-26 12:30:47 -07002168
Sudheer Shanka2250d562016-11-07 15:41:02 -08002169 // Constants for the data available via StorageManagerService.getField.
Elliott Hughesf839b4f2014-09-26 12:30:47 -07002170 /** @hide */
2171 public static final String SYSTEM_LOCALE_KEY = "SystemLocale";
2172 /** @hide */
2173 public static final String OWNER_INFO_KEY = "OwnerInfo";
2174 /** @hide */
2175 public static final String PATTERN_VISIBLE_KEY = "PatternVisible";
Paul Lawrenced8fdb332015-05-18 13:26:11 -07002176 /** @hide */
2177 public static final String PASSWORD_VISIBLE_KEY = "PasswordVisible";
San Mehatb1043402010-02-05 08:26:50 -08002178}