blob: f4deeedae69747fb65a67c3bc58ebfcbd12f1102 [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 Sharkeya4d34d92017-04-27 11:21:41 -060028import android.annotation.WorkerThread;
Jeff Sharkeyb31afd22017-06-12 14:17:10 -060029import android.app.Activity;
Svet Ganov6ee871e2015-07-10 14:29:33 -070030import android.app.ActivityThread;
Jeff Sharkeybe722152013-02-15 16:56:38 -080031import android.content.ContentResolver;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070032import android.content.Context;
Jeff Sharkeya4d34d92017-04-27 11:21:41 -060033import android.content.Intent;
Jeff Sharkey9bed0702017-01-23 20:37:05 -070034import android.content.pm.ApplicationInfo;
Jeff Sharkey275e3e42015-04-24 16:10:32 -070035import android.content.pm.IPackageMoveObserver;
36import android.content.pm.PackageManager;
Jeff Sharkeyce18c812016-04-27 16:00:41 -060037import android.os.Binder;
Mike Lockwoodcba928c2011-08-17 15:58:52 -070038import android.os.Environment;
Jeff Sharkey48877892015-03-18 11:27:19 -070039import android.os.FileUtils;
San Mehatb1043402010-02-05 08:26:50 -080040import android.os.Handler;
Jeff Sharkey41cd6812017-09-11 10:32:17 -060041import android.os.IVold;
Jeff Sharkey7e19f532017-11-06 13:54:11 -070042import android.os.IVoldTaskListener;
Kenny Roota02b8b02010-08-05 16:14:17 -070043import android.os.Looper;
San Mehatb1043402010-02-05 08:26:50 -080044import android.os.Message;
Daichi Hirono9e8d9e22015-11-13 14:37:00 +090045import android.os.ParcelFileDescriptor;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -070046import android.os.ParcelableException;
Jeff Sharkey7e19f532017-11-06 13:54:11 -070047import android.os.PersistableBundle;
Jeff Sharkey9bed0702017-01-23 20:37:05 -070048import android.os.ProxyFileDescriptorCallback;
Kenny Roota02b8b02010-08-05 16:14:17 -070049import android.os.RemoteException;
San Mehatb1043402010-02-05 08:26:50 -080050import android.os.ServiceManager;
Jeff Sharkey49ca5292016-05-10 12:54:45 -060051import android.os.ServiceManager.ServiceNotFoundException;
Jeff Sharkeyba512352015-11-12 20:17:45 -080052import android.os.SystemProperties;
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -060053import android.os.UserHandle;
Jeff Sharkeybe722152013-02-15 16:56:38 -080054import android.provider.Settings;
Jeff Sharkey9bed0702017-01-23 20:37:05 -070055import android.system.ErrnoException;
56import android.system.Os;
57import android.system.OsConstants;
Jeff Sharkey59d577a2015-04-11 21:27:21 -070058import android.text.TextUtils;
Jeff Sharkey9f2dc052018-01-07 16:47:31 -070059import android.util.DataUnit;
San Mehatb1043402010-02-05 08:26:50 -080060import android.util.Log;
Felipe Leme281389a2016-10-10 17:12:20 -070061import android.util.Pair;
Jeff Sharkeyb42d6942015-04-28 22:25:26 -070062import android.util.Slog;
Kenny Rootaf9d6672010-10-08 09:21:39 -070063import android.util.SparseArray;
Jeff Sharkey9bed0702017-01-23 20:37:05 -070064
Daichi Hirono9fb00182016-11-08 14:12:17 +090065import com.android.internal.annotations.GuardedBy;
66import com.android.internal.annotations.VisibleForTesting;
Daichi Hironod61817e2017-02-13 10:37:11 +090067import com.android.internal.logging.MetricsLogger;
Daichi Hirono9fb00182016-11-08 14:12:17 +090068import com.android.internal.os.AppFuseMount;
69import com.android.internal.os.FuseAppLoop;
Daichi Hirono812c95d2017-02-08 16:20:20 +090070import com.android.internal.os.FuseUnavailableMountException;
John Reckaa67f682016-09-20 14:24:21 -070071import com.android.internal.os.RoSystemProperties;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070072import com.android.internal.os.SomeArgs;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -070073import com.android.internal.util.Preconditions;
74
75import java.io.File;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -070076import java.io.FileDescriptor;
Jeff Sharkey789a8fc2017-04-16 13:18:35 -060077import java.io.FileNotFoundException;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -070078import java.io.IOException;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -070079import java.lang.annotation.Retention;
80import java.lang.annotation.RetentionPolicy;
Kenny Root05105f72010-09-22 17:29:43 -070081import java.lang.ref.WeakReference;
Jeff Sharkey9bed0702017-01-23 20:37:05 -070082import java.nio.charset.StandardCharsets;
San Mehatb1043402010-02-05 08:26:50 -080083import java.util.ArrayList;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070084import java.util.Arrays;
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -060085import java.util.Collections;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070086import java.util.Iterator;
Kenny Root05105f72010-09-22 17:29:43 -070087import java.util.List;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070088import java.util.Objects;
Jeff Sharkey789a8fc2017-04-16 13:18:35 -060089import java.util.UUID;
Jeff Sharkey7e19f532017-11-06 13:54:11 -070090import java.util.concurrent.CompletableFuture;
Daichi Hirono9fb00182016-11-08 14:12:17 +090091import java.util.concurrent.ThreadFactory;
Jeff Sharkey7e19f532017-11-06 13:54:11 -070092import java.util.concurrent.TimeUnit;
Kenny Rootaf9d6672010-10-08 09:21:39 -070093import java.util.concurrent.atomic.AtomicInteger;
San Mehatb1043402010-02-05 08:26:50 -080094
95/**
Kenny Root05105f72010-09-22 17:29:43 -070096 * StorageManager is the interface to the systems storage service. The storage
97 * manager handles storage-related items such as Opaque Binary Blobs (OBBs).
98 * <p>
99 * OBBs contain a filesystem that maybe be encrypted on disk and mounted
100 * on-demand from an application. OBBs are a good way of providing large amounts
101 * of binary assets without packaging them into APKs as they may be multiple
102 * gigabytes in size. However, due to their size, they're most likely stored in
103 * a shared storage pool accessible from all programs. The system does not
104 * guarantee the security of the OBB file itself: if any program modifies the
105 * OBB, there is no guarantee that a read from that OBB will produce the
106 * expected output.
San Mehatb1043402010-02-05 08:26:50 -0800107 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600108@SystemService(Context.STORAGE_SERVICE)
Jeff Sharkeybe722152013-02-15 16:56:38 -0800109public class StorageManager {
San Mehatb1043402010-02-05 08:26:50 -0800110 private static final String TAG = "StorageManager";
111
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700112 /** {@hide} */
113 public static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical";
Jeff Sharkey74acbbb2015-04-21 12:14:03 -0700114 /** {@hide} */
Jeff Sharkey0d838a02015-05-13 13:54:30 -0700115 public static final String PROP_HAS_ADOPTABLE = "vold.has_adoptable";
116 /** {@hide} */
Jeff Sharkey55fe0d02018-01-08 10:41:47 -0700117 public static final String PROP_HAS_RESERVED = "vold.has_reserved";
118 /** {@hide} */
Jeff Sharkey74acbbb2015-04-21 12:14:03 -0700119 public static final String PROP_FORCE_ADOPTABLE = "persist.fw.force_adoptable";
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800120 /** {@hide} */
Jeff Sharkeyba512352015-11-12 20:17:45 -0800121 public static final String PROP_EMULATE_FBE = "persist.sys.emulate_fbe";
Jeff Sharkey33dd1562016-04-07 11:05:33 -0600122 /** {@hide} */
123 public static final String PROP_SDCARDFS = "persist.sys.sdcardfs";
Jeff Sharkeye53e2d92017-03-25 23:14:06 -0600124 /** {@hide} */
125 public static final String PROP_VIRTUAL_DISK = "persist.sys.virtual_disk";
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700126
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700127 /** {@hide} */
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700128 public static final String UUID_PRIVATE_INTERNAL = null;
129 /** {@hide} */
130 public static final String UUID_PRIMARY_PHYSICAL = "primary_physical";
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600131 /** {@hide} */
132 public static final String UUID_SYSTEM = "system";
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700133
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600134 // NOTE: UUID constants below are namespaced
135 // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad default
136 // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad primary_physical
137 // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad system
Daniel Nishi690346b2016-06-17 10:21:48 -0700138
139 /**
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600140 * UUID representing the default internal storage of this device which
141 * provides {@link Environment#getDataDirectory()}.
Daniel Nishi690346b2016-06-17 10:21:48 -0700142 * <p>
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600143 * This value is constant across all devices and it will never change, and
144 * thus it cannot be used to uniquely identify a particular physical device.
145 *
146 * @see #getUuidForPath(File)
Jeff Sharkeya4d34d92017-04-27 11:21:41 -0600147 * @see ApplicationInfo#storageUuid
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600148 */
149 public static final UUID UUID_DEFAULT = UUID
150 .fromString("41217664-9172-527a-b3d5-edabb50a7d69");
151
152 /** {@hide} */
153 public static final UUID UUID_PRIMARY_PHYSICAL_ = UUID
154 .fromString("0f95a519-dae7-5abf-9519-fbd6209e05fd");
155
156 /** {@hide} */
157 public static final UUID UUID_SYSTEM_ = UUID
158 .fromString("5d258386-e60d-59e3-826d-0089cdd42cc0");
159
160 /**
161 * Activity Action: Allows the user to manage their storage. This activity
162 * provides the ability to free up space on the device by deleting data such
163 * as apps.
Daniel Nishi690346b2016-06-17 10:21:48 -0700164 * <p>
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600165 * If the sending application has a specific storage device or allocation
166 * size in mind, they can optionally define {@link #EXTRA_UUID} or
167 * {@link #EXTRA_REQUESTED_BYTES}, respectively.
Jeff Sharkeyb31afd22017-06-12 14:17:10 -0600168 * <p>
169 * This intent should be launched using
170 * {@link Activity#startActivityForResult(Intent, int)} so that the user
171 * knows which app is requesting the storage space. The returned result will
172 * be {@link Activity#RESULT_OK} if the requested space was made available,
173 * or {@link Activity#RESULT_CANCELED} otherwise.
Daniel Nishi690346b2016-06-17 10:21:48 -0700174 */
175 @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600176 public static final String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
177
178 /**
179 * Extra {@link UUID} used to indicate the storage volume where an
180 * application is interested in allocating or managing disk space.
181 *
182 * @see #ACTION_MANAGE_STORAGE
183 * @see #UUID_DEFAULT
184 * @see #getUuidForPath(File)
Jeff Sharkeya4d34d92017-04-27 11:21:41 -0600185 * @see Intent#putExtra(String, java.io.Serializable)
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600186 */
187 public static final String EXTRA_UUID = "android.os.storage.extra.UUID";
188
189 /**
190 * Extra used to indicate the total size (in bytes) that an application is
191 * interested in allocating.
192 * <p>
193 * When defined, the management UI will help guide the user to free up
194 * enough disk space to reach this requested value.
195 *
196 * @see #ACTION_MANAGE_STORAGE
197 */
198 public static final String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES";
Daniel Nishi690346b2016-06-17 10:21:48 -0700199
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700200 /** {@hide} */
201 public static final int DEBUG_FORCE_ADOPTABLE = 1 << 0;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800202 /** {@hide} */
203 public static final int DEBUG_EMULATE_FBE = 1 << 1;
Jeff Sharkey33dd1562016-04-07 11:05:33 -0600204 /** {@hide} */
205 public static final int DEBUG_SDCARDFS_FORCE_ON = 1 << 2;
206 /** {@hide} */
207 public static final int DEBUG_SDCARDFS_FORCE_OFF = 1 << 3;
Jeff Sharkeye53e2d92017-03-25 23:14:06 -0600208 /** {@hide} */
209 public static final int DEBUG_VIRTUAL_DISK = 1 << 4;
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700210
Jeff Sharkey47f71082016-02-01 17:03:54 -0700211 // NOTE: keep in sync with installd
Jeff Sharkey46349872015-07-28 10:49:47 -0700212 /** {@hide} */
Jeff Sharkey47f71082016-02-01 17:03:54 -0700213 public static final int FLAG_STORAGE_DE = 1 << 0;
214 /** {@hide} */
215 public static final int FLAG_STORAGE_CE = 1 << 1;
216
217 /** {@hide} */
218 public static final int FLAG_FOR_WRITE = 1 << 8;
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -0600219 /** {@hide} */
220 public static final int FLAG_REAL_STATE = 1 << 9;
221 /** {@hide} */
222 public static final int FLAG_INCLUDE_INVISIBLE = 1 << 10;
Jeff Sharkey46349872015-07-28 10:49:47 -0700223
Jeff Sharkey31d0b702016-11-21 14:16:53 -0700224 /** {@hide} */
Jeff Sharkey41cd6812017-09-11 10:32:17 -0600225 public static final int FSTRIM_FLAG_DEEP = IVold.FSTRIM_FLAG_DEEP_TRIM;
Jeff Sharkey31d0b702016-11-21 14:16:53 -0700226
Sudheer Shankaf7341142016-10-18 17:15:18 -0700227 /** @hide The volume is not encrypted. */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600228 public static final int ENCRYPTION_STATE_NONE =
229 IVold.ENCRYPTION_STATE_NONE;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700230
231 /** @hide The volume has been encrypted succesfully. */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600232 public static final int ENCRYPTION_STATE_OK =
233 IVold.ENCRYPTION_STATE_OK;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700234
Jeff Sharkey43e12112017-09-12 16:31:45 -0600235 /** @hide The volume is in a bad state. */
236 public static final int ENCRYPTION_STATE_ERROR_UNKNOWN =
237 IVold.ENCRYPTION_STATE_ERROR_UNKNOWN;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700238
239 /** @hide Encryption is incomplete */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600240 public static final int ENCRYPTION_STATE_ERROR_INCOMPLETE =
241 IVold.ENCRYPTION_STATE_ERROR_INCOMPLETE;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700242
243 /** @hide Encryption is incomplete and irrecoverable */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600244 public static final int ENCRYPTION_STATE_ERROR_INCONSISTENT =
245 IVold.ENCRYPTION_STATE_ERROR_INCONSISTENT;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700246
247 /** @hide Underlying data is corrupt */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600248 public static final int ENCRYPTION_STATE_ERROR_CORRUPT =
249 IVold.ENCRYPTION_STATE_ERROR_CORRUPT;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700250
Sudheer Shanka2250d562016-11-07 15:41:02 -0800251 private static volatile IStorageManager sStorageManager = null;
Felipe Leme179923a2016-07-19 09:33:31 -0700252
Jeff Sharkey48877892015-03-18 11:27:19 -0700253 private final Context mContext;
Jeff Sharkeybe722152013-02-15 16:56:38 -0800254 private final ContentResolver mResolver;
255
Sudheer Shanka2250d562016-11-07 15:41:02 -0800256 private final IStorageManager mStorageManager;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700257 private final Looper mLooper;
258 private final AtomicInteger mNextNonce = new AtomicInteger(0);
San Mehatb1043402010-02-05 08:26:50 -0800259
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700260 private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>();
San Mehatb1043402010-02-05 08:26:50 -0800261
Sudheer Shanka2250d562016-11-07 15:41:02 -0800262 private static class StorageEventListenerDelegate extends IStorageEventListener.Stub implements
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700263 Handler.Callback {
264 private static final int MSG_STORAGE_STATE_CHANGED = 1;
265 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700266 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
267 private static final int MSG_VOLUME_FORGOTTEN = 4;
268 private static final int MSG_DISK_SCANNED = 5;
Makoto Onuki9dc575d2015-06-12 16:10:25 -0700269 private static final int MSG_DISK_DESTROYED = 6;
San Mehatb1043402010-02-05 08:26:50 -0800270
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700271 final StorageEventListener mCallback;
272 final Handler mHandler;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700273
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700274 public StorageEventListenerDelegate(StorageEventListener callback, Looper looper) {
275 mCallback = callback;
276 mHandler = new Handler(looper, this);
San Mehatb1043402010-02-05 08:26:50 -0800277 }
278
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700279 @Override
280 public boolean handleMessage(Message msg) {
281 final SomeArgs args = (SomeArgs) msg.obj;
282 switch (msg.what) {
283 case MSG_STORAGE_STATE_CHANGED:
284 mCallback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
285 (String) args.arg3);
286 args.recycle();
287 return true;
288 case MSG_VOLUME_STATE_CHANGED:
289 mCallback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
290 args.recycle();
291 return true;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700292 case MSG_VOLUME_RECORD_CHANGED:
293 mCallback.onVolumeRecordChanged((VolumeRecord) args.arg1);
294 args.recycle();
295 return true;
296 case MSG_VOLUME_FORGOTTEN:
297 mCallback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700298 args.recycle();
299 return true;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700300 case MSG_DISK_SCANNED:
301 mCallback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700302 args.recycle();
303 return true;
Makoto Onuki9dc575d2015-06-12 16:10:25 -0700304 case MSG_DISK_DESTROYED:
305 mCallback.onDiskDestroyed((DiskInfo) args.arg1);
306 args.recycle();
307 return true;
San Mehatb1043402010-02-05 08:26:50 -0800308 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700309 args.recycle();
310 return false;
311 }
312
313 @Override
314 public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException {
315 // Ignored
316 }
317
318 @Override
319 public void onStorageStateChanged(String path, String oldState, String newState) {
320 final SomeArgs args = SomeArgs.obtain();
321 args.arg1 = path;
322 args.arg2 = oldState;
323 args.arg3 = newState;
324 mHandler.obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
325 }
326
327 @Override
328 public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
329 final SomeArgs args = SomeArgs.obtain();
330 args.arg1 = vol;
331 args.argi2 = oldState;
332 args.argi3 = newState;
333 mHandler.obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
San Mehatb1043402010-02-05 08:26:50 -0800334 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700335
336 @Override
Jeff Sharkey50a05452015-04-29 11:24:52 -0700337 public void onVolumeRecordChanged(VolumeRecord rec) {
338 final SomeArgs args = SomeArgs.obtain();
339 args.arg1 = rec;
340 mHandler.obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
341 }
342
343 @Override
344 public void onVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700345 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700346 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700347 mHandler.obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700348 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700349
350 @Override
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700351 public void onDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700352 final SomeArgs args = SomeArgs.obtain();
353 args.arg1 = disk;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700354 args.argi2 = volumeCount;
355 mHandler.obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700356 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -0700357
358 @Override
359 public void onDiskDestroyed(DiskInfo disk) throws RemoteException {
360 final SomeArgs args = SomeArgs.obtain();
361 args.arg1 = disk;
362 mHandler.obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
363 }
San Mehatb1043402010-02-05 08:26:50 -0800364 }
365
366 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700367 * Binder listener for OBB action results.
368 */
Kenny Root05105f72010-09-22 17:29:43 -0700369 private final ObbActionListener mObbActionListener = new ObbActionListener();
370
371 private class ObbActionListener extends IObbActionListener.Stub {
Gilles Debunne37051cd2011-05-25 16:27:13 -0700372 @SuppressWarnings("hiding")
Kenny Rootaf9d6672010-10-08 09:21:39 -0700373 private SparseArray<ObbListenerDelegate> mListeners = new SparseArray<ObbListenerDelegate>();
Kenny Root05105f72010-09-22 17:29:43 -0700374
Kenny Roota02b8b02010-08-05 16:14:17 -0700375 @Override
Gilles Debunne37051cd2011-05-25 16:27:13 -0700376 public void onObbResult(String filename, int nonce, int status) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700377 final ObbListenerDelegate delegate;
Kenny Root05105f72010-09-22 17:29:43 -0700378 synchronized (mListeners) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700379 delegate = mListeners.get(nonce);
380 if (delegate != null) {
381 mListeners.remove(nonce);
Kenny Root05105f72010-09-22 17:29:43 -0700382 }
383 }
Kenny Rootaf9d6672010-10-08 09:21:39 -0700384
385 if (delegate != null) {
386 delegate.sendObbStateChanged(filename, status);
387 }
Kenny Root05105f72010-09-22 17:29:43 -0700388 }
389
Kenny Rootaf9d6672010-10-08 09:21:39 -0700390 public int addListener(OnObbStateChangeListener listener) {
391 final ObbListenerDelegate delegate = new ObbListenerDelegate(listener);
Kenny Root05105f72010-09-22 17:29:43 -0700392
393 synchronized (mListeners) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700394 mListeners.put(delegate.nonce, delegate);
Kenny Root05105f72010-09-22 17:29:43 -0700395 }
Kenny Rootaf9d6672010-10-08 09:21:39 -0700396
397 return delegate.nonce;
Kenny Root05105f72010-09-22 17:29:43 -0700398 }
399 }
400
Kenny Rootaf9d6672010-10-08 09:21:39 -0700401 private int getNextNonce() {
402 return mNextNonce.getAndIncrement();
403 }
404
Kenny Root05105f72010-09-22 17:29:43 -0700405 /**
406 * Private class containing sender and receiver code for StorageEvents.
407 */
408 private class ObbListenerDelegate {
409 private final WeakReference<OnObbStateChangeListener> mObbEventListenerRef;
410 private final Handler mHandler;
411
Kenny Rootaf9d6672010-10-08 09:21:39 -0700412 private final int nonce;
413
Kenny Root05105f72010-09-22 17:29:43 -0700414 ObbListenerDelegate(OnObbStateChangeListener listener) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700415 nonce = getNextNonce();
Kenny Root05105f72010-09-22 17:29:43 -0700416 mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700417 mHandler = new Handler(mLooper) {
Kenny Root05105f72010-09-22 17:29:43 -0700418 @Override
419 public void handleMessage(Message msg) {
Gilles Debunne37051cd2011-05-25 16:27:13 -0700420 final OnObbStateChangeListener changeListener = getListener();
421 if (changeListener == null) {
Kenny Root05105f72010-09-22 17:29:43 -0700422 return;
423 }
424
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700425 changeListener.onObbStateChange((String) msg.obj, msg.arg1);
Kenny Root05105f72010-09-22 17:29:43 -0700426 }
427 };
428 }
429
430 OnObbStateChangeListener getListener() {
431 if (mObbEventListenerRef == null) {
432 return null;
433 }
434 return mObbEventListenerRef.get();
435 }
436
Kenny Rootaf9d6672010-10-08 09:21:39 -0700437 void sendObbStateChanged(String path, int state) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700438 mHandler.obtainMessage(0, state, 0, path).sendToTarget();
San Mehatb1043402010-02-05 08:26:50 -0800439 }
440 }
441
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700442 /** {@hide} */
Jeff Sharkey50a05452015-04-29 11:24:52 -0700443 @Deprecated
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700444 public static StorageManager from(Context context) {
Jeff Sharkey50a05452015-04-29 11:24:52 -0700445 return context.getSystemService(StorageManager.class);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700446 }
447
San Mehatb1043402010-02-05 08:26:50 -0800448 /**
449 * Constructs a StorageManager object through which an application can
450 * can communicate with the systems mount service.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900451 *
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600452 * @param looper The {@link android.os.Looper} which events will be received on.
San Mehatb1043402010-02-05 08:26:50 -0800453 *
454 * <p>Applications can get instance of this class by calling
455 * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
456 * of {@link android.content.Context#STORAGE_SERVICE}.
457 *
458 * @hide
459 */
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600460 public StorageManager(Context context, Looper looper) throws ServiceNotFoundException {
Jeff Sharkey48877892015-03-18 11:27:19 -0700461 mContext = context;
462 mResolver = context.getContentResolver();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700463 mLooper = looper;
Sudheer Shanka2250d562016-11-07 15:41:02 -0800464 mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getServiceOrThrow("mount"));
San Mehatb1043402010-02-05 08:26:50 -0800465 }
466
San Mehatb1043402010-02-05 08:26:50 -0800467 /**
468 * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}.
469 *
470 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
471 *
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800472 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800473 */
474 public void registerListener(StorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700475 synchronized (mDelegates) {
476 final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(listener,
477 mLooper);
478 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800479 mStorageManager.registerListener(delegate);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700480 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700481 throw e.rethrowFromSystemServer();
Chuanxia Dong6614bb62012-05-29 12:28:24 +0800482 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700483 mDelegates.add(delegate);
San Mehatb1043402010-02-05 08:26:50 -0800484 }
485 }
486
487 /**
488 * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}.
489 *
490 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
491 *
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800492 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800493 */
494 public void unregisterListener(StorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700495 synchronized (mDelegates) {
496 for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) {
497 final StorageEventListenerDelegate delegate = i.next();
498 if (delegate.mCallback == listener) {
499 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800500 mStorageManager.unregisterListener(delegate);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700501 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700502 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700503 }
504 i.remove();
505 }
506 }
San Mehatb1043402010-02-05 08:26:50 -0800507 }
San Mehatb1043402010-02-05 08:26:50 -0800508 }
509
510 /**
511 * Enables USB Mass Storage (UMS) on the device.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800512 *
513 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800514 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700515 @Deprecated
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800516 public void enableUsbMassStorage() {
San Mehatb1043402010-02-05 08:26:50 -0800517 }
518
519 /**
520 * Disables USB Mass Storage (UMS) on the device.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800521 *
522 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800523 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700524 @Deprecated
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800525 public void disableUsbMassStorage() {
San Mehatb1043402010-02-05 08:26:50 -0800526 }
527
528 /**
529 * Query if a USB Mass Storage (UMS) host is connected.
530 * @return true if UMS host is connected.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800531 *
532 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800533 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700534 @Deprecated
San Mehatb1043402010-02-05 08:26:50 -0800535 public boolean isUsbMassStorageConnected() {
San Mehatb1043402010-02-05 08:26:50 -0800536 return false;
537 }
538
539 /**
540 * Query if a USB Mass Storage (UMS) is enabled on the device.
541 * @return true if UMS host is enabled.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800542 *
543 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800544 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700545 @Deprecated
San Mehatb1043402010-02-05 08:26:50 -0800546 public boolean isUsbMassStorageEnabled() {
San Mehatb1043402010-02-05 08:26:50 -0800547 return false;
548 }
Kenny Root02c87302010-07-01 08:10:18 -0700549
550 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700551 * Mount an Opaque Binary Blob (OBB) file. If a <code>key</code> is
552 * specified, it is supplied to the mounting process to be used in any
553 * encryption used in the OBB.
554 * <p>
Kenny Root05105f72010-09-22 17:29:43 -0700555 * The OBB will remain mounted for as long as the StorageManager reference
556 * is held by the application. As soon as this reference is lost, the OBBs
Kenny Rootaf9d6672010-10-08 09:21:39 -0700557 * in use will be unmounted. The {@link OnObbStateChangeListener} registered
558 * with this call will receive the success or failure of this operation.
Kenny Root05105f72010-09-22 17:29:43 -0700559 * <p>
Kenny Roota02b8b02010-08-05 16:14:17 -0700560 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
561 * file matches a package ID that is owned by the calling program's UID.
Kenny Root05105f72010-09-22 17:29:43 -0700562 * That is, shared UID applications can attempt to mount any other
Kenny Roota02b8b02010-08-05 16:14:17 -0700563 * application's OBB that shares its UID.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900564 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700565 * @param rawPath the path to the OBB file
Kenny Root05105f72010-09-22 17:29:43 -0700566 * @param key secret used to encrypt the OBB; may be <code>null</code> if no
567 * encryption was used on the OBB.
Kenny Rootaf9d6672010-10-08 09:21:39 -0700568 * @param listener will receive the success or failure of the operation
Kenny Roota02b8b02010-08-05 16:14:17 -0700569 * @return whether the mount call was successfully queued or not
Kenny Root02c87302010-07-01 08:10:18 -0700570 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700571 public boolean mountObb(String rawPath, String key, OnObbStateChangeListener listener) {
572 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
573 Preconditions.checkNotNull(listener, "listener cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700574
Kenny Root02c87302010-07-01 08:10:18 -0700575 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700576 final String canonicalPath = new File(rawPath).getCanonicalPath();
Kenny Rootaf9d6672010-10-08 09:21:39 -0700577 final int nonce = mObbActionListener.addListener(listener);
Sudheer Shanka2250d562016-11-07 15:41:02 -0800578 mStorageManager.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce);
Kenny Roota02b8b02010-08-05 16:14:17 -0700579 return true;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700580 } catch (IOException e) {
581 throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e);
Kenny Root02c87302010-07-01 08:10:18 -0700582 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700583 throw e.rethrowFromSystemServer();
Kenny Root02c87302010-07-01 08:10:18 -0700584 }
Kenny Root02c87302010-07-01 08:10:18 -0700585 }
586
587 /**
Kenny Root05105f72010-09-22 17:29:43 -0700588 * Unmount an Opaque Binary Blob (OBB) file asynchronously. If the
589 * <code>force</code> flag is true, it will kill any application needed to
590 * unmount the given OBB (even the calling application).
591 * <p>
Kenny Rootaf9d6672010-10-08 09:21:39 -0700592 * The {@link OnObbStateChangeListener} registered with this call will
593 * receive the success or failure of this operation.
Kenny Roota02b8b02010-08-05 16:14:17 -0700594 * <p>
595 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
596 * file matches a package ID that is owned by the calling program's UID.
597 * That is, shared UID applications can obtain access to any other
598 * application's OBB that shares its UID.
Kenny Root02ca31f2010-08-12 07:36:02 -0700599 * <p>
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900600 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700601 * @param rawPath path to the OBB file
Kenny Roota02b8b02010-08-05 16:14:17 -0700602 * @param force whether to kill any programs using this in order to unmount
603 * it
Kenny Rootaf9d6672010-10-08 09:21:39 -0700604 * @param listener will receive the success or failure of the operation
Kenny Roota02b8b02010-08-05 16:14:17 -0700605 * @return whether the unmount call was successfully queued or not
Kenny Root02c87302010-07-01 08:10:18 -0700606 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700607 public boolean unmountObb(String rawPath, boolean force, OnObbStateChangeListener listener) {
608 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
609 Preconditions.checkNotNull(listener, "listener cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700610
Kenny Root02c87302010-07-01 08:10:18 -0700611 try {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700612 final int nonce = mObbActionListener.addListener(listener);
Sudheer Shanka2250d562016-11-07 15:41:02 -0800613 mStorageManager.unmountObb(rawPath, force, mObbActionListener, nonce);
Kenny Roota02b8b02010-08-05 16:14:17 -0700614 return true;
Kenny Root02c87302010-07-01 08:10:18 -0700615 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700616 throw e.rethrowFromSystemServer();
Kenny Root02c87302010-07-01 08:10:18 -0700617 }
Kenny Root02c87302010-07-01 08:10:18 -0700618 }
619
Kenny Roota02b8b02010-08-05 16:14:17 -0700620 /**
621 * Check whether an Opaque Binary Blob (OBB) is mounted or not.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900622 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700623 * @param rawPath path to OBB image
Kenny Roota02b8b02010-08-05 16:14:17 -0700624 * @return true if OBB is mounted; false if not mounted or on error
625 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700626 public boolean isObbMounted(String rawPath) {
627 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700628
Kenny Root02c87302010-07-01 08:10:18 -0700629 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800630 return mStorageManager.isObbMounted(rawPath);
Kenny Root02c87302010-07-01 08:10:18 -0700631 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700632 throw e.rethrowFromSystemServer();
Kenny Root02c87302010-07-01 08:10:18 -0700633 }
Kenny Root02c87302010-07-01 08:10:18 -0700634 }
635
636 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700637 * Check the mounted path of an Opaque Binary Blob (OBB) file. This will
638 * give you the path to where you can obtain access to the internals of the
639 * OBB.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900640 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700641 * @param rawPath path to OBB image
Kenny Roota02b8b02010-08-05 16:14:17 -0700642 * @return absolute path to mounted OBB image data or <code>null</code> if
643 * not mounted or exception encountered trying to read status
Kenny Root02c87302010-07-01 08:10:18 -0700644 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700645 public String getMountedObbPath(String rawPath) {
646 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700647
Kenny Root02c87302010-07-01 08:10:18 -0700648 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800649 return mStorageManager.getMountedObbPath(rawPath);
Kenny Root02c87302010-07-01 08:10:18 -0700650 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700651 throw e.rethrowFromSystemServer();
Kenny Root02c87302010-07-01 08:10:18 -0700652 }
Kenny Root02c87302010-07-01 08:10:18 -0700653 }
Mike Lockwoodd967f462011-03-24 08:12:30 -0700654
Jeff Sharkey48877892015-03-18 11:27:19 -0700655 /** {@hide} */
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700656 public @NonNull List<DiskInfo> getDisks() {
657 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800658 return Arrays.asList(mStorageManager.getDisks());
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700659 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700660 throw e.rethrowFromSystemServer();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700661 }
662 }
663
664 /** {@hide} */
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700665 public @Nullable DiskInfo findDiskById(String id) {
666 Preconditions.checkNotNull(id);
667 // TODO; go directly to service to make this faster
668 for (DiskInfo disk : getDisks()) {
669 if (Objects.equals(disk.id, id)) {
670 return disk;
671 }
672 }
673 return null;
674 }
675
676 /** {@hide} */
677 public @Nullable VolumeInfo findVolumeById(String id) {
678 Preconditions.checkNotNull(id);
679 // TODO; go directly to service to make this faster
680 for (VolumeInfo vol : getVolumes()) {
681 if (Objects.equals(vol.id, id)) {
682 return vol;
683 }
684 }
685 return null;
686 }
687
688 /** {@hide} */
689 public @Nullable VolumeInfo findVolumeByUuid(String fsUuid) {
690 Preconditions.checkNotNull(fsUuid);
691 // TODO; go directly to service to make this faster
692 for (VolumeInfo vol : getVolumes()) {
693 if (Objects.equals(vol.fsUuid, fsUuid)) {
694 return vol;
695 }
696 }
697 return null;
698 }
699
700 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700701 public @Nullable VolumeRecord findRecordByUuid(String fsUuid) {
702 Preconditions.checkNotNull(fsUuid);
703 // TODO; go directly to service to make this faster
704 for (VolumeRecord rec : getVolumeRecords()) {
705 if (Objects.equals(rec.fsUuid, fsUuid)) {
706 return rec;
707 }
708 }
709 return null;
710 }
711
712 /** {@hide} */
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700713 public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700714 if (emulatedVol != null) {
715 return findVolumeById(emulatedVol.getId().replace("emulated", "private"));
716 } else {
717 return null;
718 }
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700719 }
720
721 /** {@hide} */
722 public @Nullable VolumeInfo findEmulatedForPrivate(VolumeInfo privateVol) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700723 if (privateVol != null) {
724 return findVolumeById(privateVol.getId().replace("private", "emulated"));
725 } else {
726 return null;
727 }
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700728 }
729
730 /** {@hide} */
Jeff Sharkey50a05452015-04-29 11:24:52 -0700731 public @Nullable VolumeInfo findVolumeByQualifiedUuid(String volumeUuid) {
732 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
733 return findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL);
734 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
735 return getPrimaryPhysicalVolume();
736 } else {
737 return findVolumeByUuid(volumeUuid);
738 }
739 }
740
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600741 /**
742 * Return a UUID identifying the storage volume that hosts the given
743 * filesystem path.
744 * <p>
745 * If this path is hosted by the default internal storage of the device at
746 * {@link Environment#getDataDirectory()}, the returned value will be
747 * {@link #UUID_DEFAULT}.
748 *
Jeff Sharkey4233f032017-07-15 12:58:38 -0600749 * @throws IOException when the storage device hosting the given path isn't
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600750 * present, or when it doesn't have a valid UUID.
751 */
752 public @NonNull UUID getUuidForPath(@NonNull File path) throws IOException {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700753 Preconditions.checkNotNull(path);
Jeff Sharkey00347882017-04-17 16:44:12 -0600754 final String pathString = path.getCanonicalPath();
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700755 if (FileUtils.contains(Environment.getDataDirectory().getAbsolutePath(), pathString)) {
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600756 return UUID_DEFAULT;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700757 }
758 try {
759 for (VolumeInfo vol : mStorageManager.getVolumes(0)) {
760 if (vol.path != null && FileUtils.contains(vol.path, pathString)) {
761 // TODO: verify that emulated adopted devices have UUID of
762 // underlying volume
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600763 return convert(vol.fsUuid);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700764 }
765 }
766 } catch (RemoteException e) {
767 throw e.rethrowFromSystemServer();
768 }
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600769 throw new FileNotFoundException("Failed to find a storage device for " + path);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700770 }
771
772 /** {@hide} */
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600773 public @NonNull File findPathForUuid(String volumeUuid) throws FileNotFoundException {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700774 final VolumeInfo vol = findVolumeByQualifiedUuid(volumeUuid);
775 if (vol != null) {
776 return vol.getPath();
777 }
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600778 throw new FileNotFoundException("Failed to find a storage device for " + volumeUuid);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700779 }
780
Jeff Sharkey4233f032017-07-15 12:58:38 -0600781 /**
782 * Test if the given file descriptor supports allocation of disk space using
783 * {@link #allocateBytes(FileDescriptor, long)}.
784 */
785 public boolean isAllocationSupported(@NonNull FileDescriptor fd) {
786 try {
787 getUuidForPath(ParcelFileDescriptor.getFile(fd));
788 return true;
789 } catch (IOException e) {
790 return false;
791 }
792 }
793
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700794 /** {@hide} */
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700795 public @NonNull List<VolumeInfo> getVolumes() {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700796 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800797 return Arrays.asList(mStorageManager.getVolumes(0));
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700798 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700799 throw e.rethrowFromSystemServer();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700800 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700801 }
802
803 /** {@hide} */
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700804 public @NonNull List<VolumeInfo> getWritablePrivateVolumes() {
805 try {
806 final ArrayList<VolumeInfo> res = new ArrayList<>();
Sudheer Shanka2250d562016-11-07 15:41:02 -0800807 for (VolumeInfo vol : mStorageManager.getVolumes(0)) {
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700808 if (vol.getType() == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) {
809 res.add(vol);
810 }
811 }
812 return res;
813 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700814 throw e.rethrowFromSystemServer();
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700815 }
816 }
817
818 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700819 public @NonNull List<VolumeRecord> getVolumeRecords() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700820 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800821 return Arrays.asList(mStorageManager.getVolumeRecords(0));
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700822 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700823 throw e.rethrowFromSystemServer();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700824 }
825 }
826
827 /** {@hide} */
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700828 public @Nullable String getBestVolumeDescription(VolumeInfo vol) {
Jeff Sharkey50a05452015-04-29 11:24:52 -0700829 if (vol == null) return null;
830
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700831 // Nickname always takes precedence when defined
832 if (!TextUtils.isEmpty(vol.fsUuid)) {
833 final VolumeRecord rec = findRecordByUuid(vol.fsUuid);
Jeff Sharkeyc8406812015-05-04 12:04:09 -0700834 if (rec != null && !TextUtils.isEmpty(rec.nickname)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700835 return rec.nickname;
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700836 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700837 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700838
839 if (!TextUtils.isEmpty(vol.getDescription())) {
840 return vol.getDescription();
841 }
842
843 if (vol.disk != null) {
844 return vol.disk.getDescription();
845 }
846
847 return null;
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700848 }
849
850 /** {@hide} */
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700851 public @Nullable VolumeInfo getPrimaryPhysicalVolume() {
852 final List<VolumeInfo> vols = getVolumes();
853 for (VolumeInfo vol : vols) {
854 if (vol.isPrimaryPhysical()) {
855 return vol;
856 }
857 }
858 return null;
859 }
860
861 /** {@hide} */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700862 public void mount(String volId) {
863 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800864 mStorageManager.mount(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700865 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700866 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700867 }
868 }
869
870 /** {@hide} */
871 public void unmount(String volId) {
872 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800873 mStorageManager.unmount(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700874 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700875 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700876 }
877 }
878
879 /** {@hide} */
880 public void format(String volId) {
881 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800882 mStorageManager.format(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700883 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700884 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700885 }
886 }
887
888 /** {@hide} */
Jeff Sharkey7e19f532017-11-06 13:54:11 -0700889 @Deprecated
Jeff Sharkey9756d752015-05-14 21:07:42 -0700890 public long benchmark(String volId) {
Jeff Sharkey7e19f532017-11-06 13:54:11 -0700891 final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
892 benchmark(volId, new IVoldTaskListener.Stub() {
893 @Override
894 public void onStatus(int status, PersistableBundle extras) {
895 // Ignored
896 }
897
898 @Override
899 public void onFinished(int status, PersistableBundle extras) {
900 result.complete(extras);
901 }
902 });
Jeff Sharkey9756d752015-05-14 21:07:42 -0700903 try {
Jeff Sharkey7e19f532017-11-06 13:54:11 -0700904 // Convert ms to ns
905 return result.get(3, TimeUnit.MINUTES).getLong("run", Long.MAX_VALUE) * 1000000;
906 } catch (Exception e) {
907 return Long.MAX_VALUE;
908 }
909 }
910
911 /** {@hide} */
912 public void benchmark(String volId, IVoldTaskListener listener) {
913 try {
914 mStorageManager.benchmark(volId, listener);
Jeff Sharkey9756d752015-05-14 21:07:42 -0700915 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700916 throw e.rethrowFromSystemServer();
Jeff Sharkey9756d752015-05-14 21:07:42 -0700917 }
918 }
919
920 /** {@hide} */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700921 public void partitionPublic(String diskId) {
922 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800923 mStorageManager.partitionPublic(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700924 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700925 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700926 }
927 }
928
929 /** {@hide} */
930 public void partitionPrivate(String diskId) {
931 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800932 mStorageManager.partitionPrivate(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700933 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700934 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700935 }
936 }
937
938 /** {@hide} */
939 public void partitionMixed(String diskId, int ratio) {
940 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800941 mStorageManager.partitionMixed(diskId, ratio);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700942 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700943 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700944 }
945 }
946
947 /** {@hide} */
Jeff Sharkeyb42d6942015-04-28 22:25:26 -0700948 public void wipeAdoptableDisks() {
949 // We only wipe devices in "adoptable" locations, which are in a
950 // long-term stable slot/location on the device, where apps have a
951 // reasonable chance of storing sensitive data. (Apps need to go through
952 // SAF to write to transient volumes.)
953 final List<DiskInfo> disks = getDisks();
954 for (DiskInfo disk : disks) {
955 final String diskId = disk.getId();
956 if (disk.isAdoptable()) {
957 Slog.d(TAG, "Found adoptable " + diskId + "; wiping");
958 try {
959 // TODO: switch to explicit wipe command when we have it,
960 // for now rely on the fact that vfat format does a wipe
Sudheer Shanka2250d562016-11-07 15:41:02 -0800961 mStorageManager.partitionPublic(diskId);
Jeff Sharkeyb42d6942015-04-28 22:25:26 -0700962 } catch (Exception e) {
963 Slog.w(TAG, "Failed to wipe " + diskId + ", but soldiering onward", e);
964 }
965 } else {
966 Slog.d(TAG, "Ignorning non-adoptable disk " + disk.getId());
967 }
968 }
969 }
970
971 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700972 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700973 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800974 mStorageManager.setVolumeNickname(fsUuid, nickname);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700975 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700976 throw e.rethrowFromSystemServer();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700977 }
978 }
979
980 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700981 public void setVolumeInited(String fsUuid, boolean inited) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700982 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800983 mStorageManager.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0,
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700984 VolumeRecord.USER_FLAG_INITED);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700985 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700986 throw e.rethrowFromSystemServer();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700987 }
988 }
989
990 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700991 public void setVolumeSnoozed(String fsUuid, boolean snoozed) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700992 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800993 mStorageManager.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0,
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700994 VolumeRecord.USER_FLAG_SNOOZED);
995 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700996 throw e.rethrowFromSystemServer();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700997 }
998 }
999
1000 /** {@hide} */
1001 public void forgetVolume(String fsUuid) {
1002 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001003 mStorageManager.forgetVolume(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001004 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001005 throw e.rethrowFromSystemServer();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001006 }
1007 }
1008
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001009 /**
1010 * This is not the API you're looking for.
1011 *
1012 * @see PackageManager#getPrimaryStorageCurrentVolume()
1013 * @hide
1014 */
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001015 public String getPrimaryStorageUuid() {
1016 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001017 return mStorageManager.getPrimaryStorageUuid();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001018 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001019 throw e.rethrowFromSystemServer();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001020 }
1021 }
1022
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001023 /**
1024 * This is not the API you're looking for.
1025 *
1026 * @see PackageManager#movePrimaryStorage(VolumeInfo)
1027 * @hide
1028 */
1029 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001030 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001031 mStorageManager.setPrimaryStorageUuid(volumeUuid, callback);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001032 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001033 throw e.rethrowFromSystemServer();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001034 }
1035 }
1036
Felipe Lemec250e452016-04-11 18:44:33 -07001037 /**
1038 * Return the {@link StorageVolume} that contains the given file, or {@code null} if none.
1039 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001040 public @Nullable StorageVolume getStorageVolume(File file) {
1041 return getStorageVolume(getVolumeList(), file);
1042 }
1043
1044 /** {@hide} */
1045 public static @Nullable StorageVolume getStorageVolume(File file, int userId) {
Jeff Sharkey46349872015-07-28 10:49:47 -07001046 return getStorageVolume(getVolumeList(userId, 0), file);
Jeff Sharkey48877892015-03-18 11:27:19 -07001047 }
1048
1049 /** {@hide} */
1050 private static @Nullable StorageVolume getStorageVolume(StorageVolume[] volumes, File file) {
Felipe Lemec250e452016-04-11 18:44:33 -07001051 if (file == null) {
1052 return null;
1053 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001054 try {
Jeff Sharkey983294592015-07-13 10:25:31 -07001055 file = file.getCanonicalFile();
Jeff Sharkey48877892015-03-18 11:27:19 -07001056 } catch (IOException ignored) {
Felipe Lemec250e452016-04-11 18:44:33 -07001057 Slog.d(TAG, "Could not get canonical path for " + file);
Jeff Sharkey983294592015-07-13 10:25:31 -07001058 return null;
Jeff Sharkey48877892015-03-18 11:27:19 -07001059 }
1060 for (StorageVolume volume : volumes) {
Jeff Sharkey983294592015-07-13 10:25:31 -07001061 File volumeFile = volume.getPathFile();
1062 try {
1063 volumeFile = volumeFile.getCanonicalFile();
1064 } catch (IOException ignored) {
1065 continue;
Jeff Sharkey48877892015-03-18 11:27:19 -07001066 }
Jeff Sharkey983294592015-07-13 10:25:31 -07001067 if (FileUtils.contains(volumeFile, file)) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001068 return volume;
1069 }
1070 }
1071 return null;
1072 }
1073
Mike Lockwoodd967f462011-03-24 08:12:30 -07001074 /**
1075 * Gets the state of a volume via its mountpoint.
1076 * @hide
1077 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001078 @Deprecated
1079 public @NonNull String getVolumeState(String mountPoint) {
1080 final StorageVolume vol = getStorageVolume(new File(mountPoint));
1081 if (vol != null) {
1082 return vol.getState();
1083 } else {
1084 return Environment.MEDIA_UNKNOWN;
Mike Lockwoodd967f462011-03-24 08:12:30 -07001085 }
1086 }
1087
Felipe Leme04a5d402016-02-08 16:44:06 -08001088 /**
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001089 * Return the list of shared/external storage volumes available to the
1090 * current user. This includes both the primary shared storage device and
1091 * any attached external volumes including SD cards and USB drives.
Felipe Leme04a5d402016-02-08 16:44:06 -08001092 *
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001093 * @see Environment#getExternalStorageDirectory()
1094 * @see StorageVolume#createAccessIntent(String)
Felipe Leme04a5d402016-02-08 16:44:06 -08001095 */
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001096 public @NonNull List<StorageVolume> getStorageVolumes() {
1097 final ArrayList<StorageVolume> res = new ArrayList<>();
1098 Collections.addAll(res,
1099 getVolumeList(UserHandle.myUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE));
1100 return res;
1101 }
1102
1103 /**
1104 * Return the primary shared/external storage volume available to the
1105 * current user. This volume is the same storage device returned by
1106 * {@link Environment#getExternalStorageDirectory()} and
1107 * {@link Context#getExternalFilesDir(String)}.
1108 */
1109 public @NonNull StorageVolume getPrimaryStorageVolume() {
1110 return getVolumeList(UserHandle.myUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE)[0];
1111 }
1112
Felipe Leme18202e00b2016-05-12 12:56:28 -07001113 /** {@hide} */
Felipe Leme281389a2016-10-10 17:12:20 -07001114 public static Pair<String, Long> getPrimaryStoragePathAndSize() {
Jeff Sharkey24403ff2017-04-04 15:09:58 -06001115 return Pair.create(null,
hj.seoe82e89ef92017-12-20 09:39:47 +09001116 FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace()
1117 + Environment.getRootDirectory().getTotalSpace()));
Felipe Leme18202e00b2016-05-12 12:56:28 -07001118 }
1119
Felipe Leme281389a2016-10-10 17:12:20 -07001120 /** {@hide} */
1121 public long getPrimaryStorageSize() {
hj.seoe82e89ef92017-12-20 09:39:47 +09001122 return FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace()
1123 + Environment.getRootDirectory().getTotalSpace());
Felipe Leme18202e00b2016-05-12 12:56:28 -07001124 }
1125
Jeff Sharkeyae266462017-11-27 13:32:24 -07001126 /** {@hide} */
1127 public void mkdirs(File file) {
1128 try {
1129 mStorageManager.mkdirs(mContext.getOpPackageName(), file.getAbsolutePath());
1130 } catch (RemoteException e) {
1131 throw e.rethrowFromSystemServer();
1132 }
1133 }
1134
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001135 /** @removed */
Jeff Sharkey48877892015-03-18 11:27:19 -07001136 public @NonNull StorageVolume[] getVolumeList() {
Jeff Sharkey46349872015-07-28 10:49:47 -07001137 return getVolumeList(mContext.getUserId(), 0);
Jeff Sharkey48877892015-03-18 11:27:19 -07001138 }
1139
1140 /** {@hide} */
Jeff Sharkey46349872015-07-28 10:49:47 -07001141 public static @NonNull StorageVolume[] getVolumeList(int userId, int flags) {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001142 final IStorageManager storageManager = IStorageManager.Stub.asInterface(
Jeff Sharkey48877892015-03-18 11:27:19 -07001143 ServiceManager.getService("mount"));
1144 try {
Svetoslav7395cbf2015-07-15 15:58:01 -07001145 String packageName = ActivityThread.currentOpPackageName();
1146 if (packageName == null) {
1147 // Package name can be null if the activity thread is running but the app
1148 // hasn't bound yet. In this case we fall back to the first package in the
1149 // current UID. This works for runtime permissions as permission state is
1150 // per UID and permission realted app ops are updated for all UID packages.
1151 String[] packageNames = ActivityThread.getPackageManager().getPackagesForUid(
1152 android.os.Process.myUid());
1153 if (packageNames == null || packageNames.length <= 0) {
1154 return new StorageVolume[0];
1155 }
1156 packageName = packageNames[0];
1157 }
Jeff Sharkeycd654482016-01-08 17:42:11 -07001158 final int uid = ActivityThread.getPackageManager().getPackageUid(packageName,
Jeff Sharkeyc5967e92016-01-07 18:50:29 -07001159 PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
Svetoslav7395cbf2015-07-15 15:58:01 -07001160 if (uid <= 0) {
1161 return new StorageVolume[0];
1162 }
Sudheer Shanka2250d562016-11-07 15:41:02 -08001163 return storageManager.getVolumeList(uid, packageName, flags);
Jeff Sharkey48877892015-03-18 11:27:19 -07001164 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001165 throw e.rethrowFromSystemServer();
Mike Lockwoodd967f462011-03-24 08:12:30 -07001166 }
1167 }
Mike Lockwood2f6a3882011-05-09 19:08:06 -07001168
1169 /**
1170 * Returns list of paths for all mountable volumes.
1171 * @hide
1172 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001173 @Deprecated
1174 public @NonNull String[] getVolumePaths() {
Mike Lockwood2f6a3882011-05-09 19:08:06 -07001175 StorageVolume[] volumes = getVolumeList();
Mike Lockwood2f6a3882011-05-09 19:08:06 -07001176 int count = volumes.length;
1177 String[] paths = new String[count];
1178 for (int i = 0; i < count; i++) {
1179 paths[i] = volumes[i].getPath();
1180 }
1181 return paths;
1182 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001183
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001184 /** @removed */
Jeff Sharkey48877892015-03-18 11:27:19 -07001185 public @NonNull StorageVolume getPrimaryVolume() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001186 return getPrimaryVolume(getVolumeList());
1187 }
1188
1189 /** {@hide} */
Jeff Sharkey48877892015-03-18 11:27:19 -07001190 public static @NonNull StorageVolume getPrimaryVolume(StorageVolume[] volumes) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001191 for (StorageVolume volume : volumes) {
1192 if (volume.isPrimary()) {
1193 return volume;
1194 }
1195 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001196 throw new IllegalStateException("Missing primary storage");
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001197 }
Jeff Sharkeybe722152013-02-15 16:56:38 -08001198
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001199 private static final int DEFAULT_THRESHOLD_PERCENTAGE = 5;
Jeff Sharkey9f2dc052018-01-07 16:47:31 -07001200 private static final long DEFAULT_THRESHOLD_MAX_BYTES = DataUnit.MEBIBYTES.toBytes(500);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001201
1202 private static final int DEFAULT_CACHE_PERCENTAGE = 10;
Jeff Sharkey9f2dc052018-01-07 16:47:31 -07001203 private static final long DEFAULT_CACHE_MAX_BYTES = DataUnit.GIBIBYTES.toBytes(5);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001204
Jeff Sharkey9f2dc052018-01-07 16:47:31 -07001205 private static final long DEFAULT_FULL_THRESHOLD_BYTES = DataUnit.MEBIBYTES.toBytes(1);
Jeff Sharkeybe722152013-02-15 16:56:38 -08001206
1207 /**
Jeff Sharkey742e7902014-08-16 19:09:13 -07001208 * Return the number of available bytes until the given path is considered
1209 * running low on storage.
1210 *
1211 * @hide
1212 */
1213 public long getStorageBytesUntilLow(File path) {
1214 return path.getUsableSpace() - getStorageFullBytes(path);
1215 }
1216
1217 /**
Jeff Sharkeybe722152013-02-15 16:56:38 -08001218 * Return the number of available bytes at which the given path is
1219 * considered running low on storage.
1220 *
1221 * @hide
1222 */
1223 public long getStorageLowBytes(File path) {
1224 final long lowPercent = Settings.Global.getInt(mResolver,
1225 Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE);
1226 final long lowBytes = (path.getTotalSpace() * lowPercent) / 100;
1227
1228 final long maxLowBytes = Settings.Global.getLong(mResolver,
1229 Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES);
1230
1231 return Math.min(lowBytes, maxLowBytes);
1232 }
1233
1234 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001235 * Return the minimum number of bytes of storage on the device that should
1236 * be reserved for cached data.
1237 *
1238 * @hide
1239 */
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001240 public long getStorageCacheBytes(File path, @AllocateFlags int flags) {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001241 final long cachePercent = Settings.Global.getInt(mResolver,
1242 Settings.Global.SYS_STORAGE_CACHE_PERCENTAGE, DEFAULT_CACHE_PERCENTAGE);
1243 final long cacheBytes = (path.getTotalSpace() * cachePercent) / 100;
1244
1245 final long maxCacheBytes = Settings.Global.getLong(mResolver,
1246 Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES, DEFAULT_CACHE_MAX_BYTES);
1247
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001248 final long result = Math.min(cacheBytes, maxCacheBytes);
1249 if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
1250 return 0;
1251 } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED) != 0) {
1252 return 0;
1253 } else if ((flags & StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED) != 0) {
1254 return result / 2;
1255 } else {
1256 return result;
1257 }
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001258 }
1259
1260 /**
Jeff Sharkeybe722152013-02-15 16:56:38 -08001261 * Return the number of available bytes at which the given path is
1262 * considered full.
1263 *
1264 * @hide
1265 */
1266 public long getStorageFullBytes(File path) {
1267 return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
1268 DEFAULT_FULL_THRESHOLD_BYTES);
1269 }
Paul Lawrencee8fdc542014-05-28 07:14:17 -07001270
Jeff Sharkey50a05452015-04-29 11:24:52 -07001271 /** {@hide} */
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01001272 public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
Paul Crowleybcf48ed2015-04-22 13:36:59 +01001273 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001274 mStorageManager.createUserKey(userId, serialNumber, ephemeral);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01001275 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001276 throw e.rethrowFromSystemServer();
Paul Crowleybcf48ed2015-04-22 13:36:59 +01001277 }
1278 }
1279
1280 /** {@hide} */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001281 public void destroyUserKey(int userId) {
Paul Crowley7ec733f2015-05-19 12:42:00 +01001282 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001283 mStorageManager.destroyUserKey(userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001284 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001285 throw e.rethrowFromSystemServer();
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001286 }
1287 }
1288
1289 /** {@hide} */
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001290 public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001291 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001292 mStorageManager.unlockUserKey(userId, serialNumber, token, secret);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001293 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001294 throw e.rethrowFromSystemServer();
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001295 }
1296 }
1297
1298 /** {@hide} */
1299 public void lockUserKey(int userId) {
1300 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001301 mStorageManager.lockUserKey(userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001302 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001303 throw e.rethrowFromSystemServer();
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001304 }
1305 }
1306
1307 /** {@hide} */
Jeff Sharkey47f71082016-02-01 17:03:54 -07001308 public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001309 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001310 mStorageManager.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001311 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001312 throw e.rethrowFromSystemServer();
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001313 }
1314 }
1315
1316 /** {@hide} */
Jeff Sharkeyfcf1e552016-04-14 20:44:58 -06001317 public void destroyUserStorage(String volumeUuid, int userId, int flags) {
1318 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001319 mStorageManager.destroyUserStorage(volumeUuid, userId, flags);
Jeff Sharkeyfcf1e552016-04-14 20:44:58 -06001320 } catch (RemoteException e) {
1321 throw e.rethrowFromSystemServer();
1322 }
1323 }
1324
1325 /** {@hide} */
Rubin Xuee67b612017-04-27 17:01:05 +01001326 public void secdiscard(String path) {
1327 try {
1328 mStorageManager.secdiscard(path);
1329 } catch (RemoteException e) {
1330 throw e.rethrowFromSystemServer();
1331 }
1332 }
1333
1334 /** {@hide} */
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001335 public static boolean isUserKeyUnlocked(int userId) {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001336 if (sStorageManager == null) {
1337 sStorageManager = IStorageManager.Stub
Jeff Sharkey4815ed42016-05-26 09:31:04 -06001338 .asInterface(ServiceManager.getService("mount"));
1339 }
Sudheer Shanka2250d562016-11-07 15:41:02 -08001340 if (sStorageManager == null) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001341 Slog.w(TAG, "Early during boot, assuming locked");
1342 return false;
1343 }
1344 final long token = Binder.clearCallingIdentity();
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001345 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001346 return sStorageManager.isUserKeyUnlocked(userId);
Paul Crowley7ec733f2015-05-19 12:42:00 +01001347 } catch (RemoteException e) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06001348 throw e.rethrowAsRuntimeException();
1349 } finally {
1350 Binder.restoreCallingIdentity(token);
Paul Crowley7ec733f2015-05-19 12:42:00 +01001351 }
1352 }
1353
Jeff Sharkeycf3f0a12016-03-17 19:57:58 -06001354 /**
Jeff Sharkeyf82c2f02016-04-12 15:19:10 -06001355 * Return if data stored at or under the given path will be encrypted while
1356 * at rest. This can help apps avoid the overhead of double-encrypting data.
Jeff Sharkeycf3f0a12016-03-17 19:57:58 -06001357 */
1358 public boolean isEncrypted(File file) {
1359 if (FileUtils.contains(Environment.getDataDirectory(), file)) {
1360 return isEncrypted();
1361 } else if (FileUtils.contains(Environment.getExpandDirectory(), file)) {
1362 return true;
1363 }
1364 // TODO: extend to support shared storage
1365 return false;
1366 }
1367
Paul Lawrence20be5d62016-02-26 13:51:17 -08001368 /** {@hide}
1369 * Is this device encryptable or already encrypted?
1370 * @return true for encryptable or encrypted
1371 * false not encrypted and not encryptable
1372 */
1373 public static boolean isEncryptable() {
John Reckaa67f682016-09-20 14:24:21 -07001374 return RoSystemProperties.CRYPTO_ENCRYPTABLE;
Paul Lawrence20be5d62016-02-26 13:51:17 -08001375 }
1376
1377 /** {@hide}
1378 * Is this device already encrypted?
1379 * @return true for encrypted. (Implies isEncryptable() == true)
1380 * false not encrypted
1381 */
1382 public static boolean isEncrypted() {
John Reckaa67f682016-09-20 14:24:21 -07001383 return RoSystemProperties.CRYPTO_ENCRYPTED;
Paul Lawrence20be5d62016-02-26 13:51:17 -08001384 }
1385
1386 /** {@hide}
1387 * Is this device file encrypted?
1388 * @return true for file encrypted. (Implies isEncrypted() == true)
1389 * false not encrypted or block encrypted
1390 */
1391 public static boolean isFileEncryptedNativeOnly() {
1392 if (!isEncrypted()) {
1393 return false;
1394 }
John Reckaa67f682016-09-20 14:24:21 -07001395 return RoSystemProperties.CRYPTO_FILE_ENCRYPTED;
Paul Lawrence20be5d62016-02-26 13:51:17 -08001396 }
1397
1398 /** {@hide}
1399 * Is this device block encrypted?
1400 * @return true for block encrypted. (Implies isEncrypted() == true)
1401 * false not encrypted or file encrypted
1402 */
1403 public static boolean isBlockEncrypted() {
1404 if (!isEncrypted()) {
1405 return false;
1406 }
John Reckaa67f682016-09-20 14:24:21 -07001407 return RoSystemProperties.CRYPTO_BLOCK_ENCRYPTED;
Paul Lawrence20be5d62016-02-26 13:51:17 -08001408 }
1409
1410 /** {@hide}
1411 * Is this device block encrypted with credentials?
1412 * @return true for crediential block encrypted.
1413 * (Implies isBlockEncrypted() == true)
1414 * false not encrypted, file encrypted or default block encrypted
1415 */
1416 public static boolean isNonDefaultBlockEncrypted() {
1417 if (!isBlockEncrypted()) {
1418 return false;
1419 }
1420
1421 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001422 IStorageManager storageManager = IStorageManager.Stub.asInterface(
Paul Lawrence20be5d62016-02-26 13:51:17 -08001423 ServiceManager.getService("mount"));
Sudheer Shanka2250d562016-11-07 15:41:02 -08001424 return storageManager.getPasswordType() != CRYPT_TYPE_DEFAULT;
Paul Lawrence20be5d62016-02-26 13:51:17 -08001425 } catch (RemoteException e) {
1426 Log.e(TAG, "Error getting encryption type");
1427 return false;
1428 }
1429 }
1430
1431 /** {@hide}
1432 * Is this device in the process of being block encrypted?
1433 * @return true for encrypting.
1434 * false otherwise
1435 * Whether device isEncrypted at this point is undefined
1436 * Note that only system services and CryptKeeper will ever see this return
1437 * true - no app will ever be launched in this state.
1438 * Also note that this state will not change without a teardown of the
1439 * framework, so no service needs to check for changes during their lifespan
1440 */
1441 public static boolean isBlockEncrypting() {
1442 final String state = SystemProperties.get("vold.encrypt_progress", "");
1443 return !"".equalsIgnoreCase(state);
1444 }
1445
1446 /** {@hide}
1447 * Is this device non default block encrypted and in the process of
1448 * prompting for credentials?
1449 * @return true for prompting for credentials.
1450 * (Implies isNonDefaultBlockEncrypted() == true)
1451 * false otherwise
1452 * Note that only system services and CryptKeeper will ever see this return
1453 * true - no app will ever be launched in this state.
1454 * Also note that this state will not change without a teardown of the
1455 * framework, so no service needs to check for changes during their lifespan
1456 */
1457 public static boolean inCryptKeeperBounce() {
1458 final String status = SystemProperties.get("vold.decrypt");
1459 return "trigger_restart_min_framework".equals(status);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001460 }
1461
1462 /** {@hide} */
Paul Lawrence20be5d62016-02-26 13:51:17 -08001463 public static boolean isFileEncryptedEmulatedOnly() {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001464 return SystemProperties.getBoolean(StorageManager.PROP_EMULATE_FBE, false);
Clara Bayarri965da392015-10-28 17:53:53 +00001465 }
1466
Paul Lawrence20be5d62016-02-26 13:51:17 -08001467 /** {@hide}
1468 * Is this device running in a file encrypted mode, either native or emulated?
1469 * @return true for file encrypted, false otherwise
1470 */
1471 public static boolean isFileEncryptedNativeOrEmulated() {
1472 return isFileEncryptedNativeOnly()
1473 || isFileEncryptedEmulatedOnly();
1474 }
1475
Clara Bayarri965da392015-10-28 17:53:53 +00001476 /** {@hide} */
Jeff Sharkey8eb783b2018-01-04 16:46:48 -07001477 public static boolean hasAdoptable() {
1478 return SystemProperties.getBoolean(PROP_HAS_ADOPTABLE, false);
1479 }
1480
1481 /** {@hide} */
Jeff Sharkey50a05452015-04-29 11:24:52 -07001482 public static File maybeTranslateEmulatedPathToInternal(File path) {
Jeff Sharkey2063e4f2017-06-06 16:03:24 -06001483 // Disabled now that FUSE has been replaced by sdcardfs
Jeff Sharkey50a05452015-04-29 11:24:52 -07001484 return path;
1485 }
1486
Daichi Hirono9e8d9e22015-11-13 14:37:00 +09001487 /** {@hide} */
Daichi Hirono9fb00182016-11-08 14:12:17 +09001488 @VisibleForTesting
1489 public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
Daichi Hirono812c95d2017-02-08 16:20:20 +09001490 int mode, ProxyFileDescriptorCallback callback, Handler handler, ThreadFactory factory)
Daichi Hirono9fb00182016-11-08 14:12:17 +09001491 throws IOException {
Daichi Hirono2443a092017-04-28 14:53:19 +09001492 Preconditions.checkNotNull(callback);
Daichi Hironod61817e2017-02-13 10:37:11 +09001493 MetricsLogger.count(mContext, "storage_open_proxy_file_descriptor", 1);
Daichi Hirono9fb00182016-11-08 14:12:17 +09001494 // Retry is needed because the mount point mFuseAppLoop is using may be unmounted before
1495 // invoking StorageManagerService#openProxyFileDescriptor. In this case, we need to re-mount
1496 // the bridge by calling mountProxyFileDescriptorBridge.
Daichi Hirono812c95d2017-02-08 16:20:20 +09001497 while (true) {
Daichi Hirono9fb00182016-11-08 14:12:17 +09001498 try {
1499 synchronized (mFuseAppLoopLock) {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001500 boolean newlyCreated = false;
Daichi Hirono9fb00182016-11-08 14:12:17 +09001501 if (mFuseAppLoop == null) {
1502 final AppFuseMount mount = mStorageManager.mountProxyFileDescriptorBridge();
1503 if (mount == null) {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001504 throw new IOException("Failed to mount proxy bridge");
Daichi Hirono9fb00182016-11-08 14:12:17 +09001505 }
Daichi Hirono812c95d2017-02-08 16:20:20 +09001506 mFuseAppLoop = new FuseAppLoop(mount.mountPointId, mount.fd, factory);
1507 newlyCreated = true;
Daichi Hirono9fb00182016-11-08 14:12:17 +09001508 }
Daichi Hirono812c95d2017-02-08 16:20:20 +09001509 if (handler == null) {
1510 handler = new Handler(Looper.getMainLooper());
1511 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09001512 try {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001513 final int fileId = mFuseAppLoop.registerCallback(callback, handler);
1514 final ParcelFileDescriptor pfd = mStorageManager.openProxyFileDescriptor(
1515 mFuseAppLoop.getMountPointId(), fileId, mode);
1516 if (pfd == null) {
1517 mFuseAppLoop.unregisterCallback(fileId);
1518 throw new FuseUnavailableMountException(
1519 mFuseAppLoop.getMountPointId());
Daichi Hirono9fb00182016-11-08 14:12:17 +09001520 }
Daichi Hirono812c95d2017-02-08 16:20:20 +09001521 return pfd;
1522 } catch (FuseUnavailableMountException exception) {
1523 // The bridge is being unmounted. Tried to recreate it unless the bridge was
1524 // just created.
1525 if (newlyCreated) {
1526 throw new IOException(exception);
1527 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09001528 mFuseAppLoop = null;
1529 continue;
1530 }
1531 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09001532 } catch (RemoteException e) {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001533 // Cannot recover from remote exception.
1534 throw new IOException(e);
Daichi Hirono9fb00182016-11-08 14:12:17 +09001535 }
1536 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09001537 }
1538
Daichi Hirono2443a092017-04-28 14:53:19 +09001539 /** {@hide} */
Daichi Hirono9fb00182016-11-08 14:12:17 +09001540 public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
1541 int mode, ProxyFileDescriptorCallback callback)
1542 throws IOException {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001543 return openProxyFileDescriptor(mode, callback, null, null);
Daichi Hirono9fb00182016-11-08 14:12:17 +09001544 }
1545
Daichi Hirono812c95d2017-02-08 16:20:20 +09001546 /**
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001547 * Opens a seekable {@link ParcelFileDescriptor} that proxies all low-level
1548 * I/O requests back to the given {@link ProxyFileDescriptorCallback}.
1549 * <p>
1550 * This can be useful when you want to provide quick access to a large file
1551 * that isn't backed by a real file on disk, such as a file on a network
1552 * share, cloud storage service, etc. As an example, you could respond to a
1553 * {@link ContentResolver#openFileDescriptor(android.net.Uri, String)}
1554 * request by returning a {@link ParcelFileDescriptor} created with this
1555 * method, and then stream the content on-demand as requested.
1556 * <p>
1557 * Another useful example might be where you have an encrypted file that
1558 * you're willing to decrypt on-demand, but where you want to avoid
1559 * persisting the cleartext version.
Daichi Hirono812c95d2017-02-08 16:20:20 +09001560 *
1561 * @param mode The desired access mode, must be one of
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001562 * {@link ParcelFileDescriptor#MODE_READ_ONLY},
1563 * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or
1564 * {@link ParcelFileDescriptor#MODE_READ_WRITE}
1565 * @param callback Callback to process file operation requests issued on
1566 * returned file descriptor.
Daichi Hirono812c95d2017-02-08 16:20:20 +09001567 * @param handler Handler that invokes callback methods.
1568 * @return Seekable ParcelFileDescriptor.
1569 * @throws IOException
1570 */
1571 public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
1572 int mode, ProxyFileDescriptorCallback callback, Handler handler)
1573 throws IOException {
Daichi Hirono2443a092017-04-28 14:53:19 +09001574 Preconditions.checkNotNull(handler);
Daichi Hirono812c95d2017-02-08 16:20:20 +09001575 return openProxyFileDescriptor(mode, callback, handler, null);
1576 }
1577
Daichi Hirono9fb00182016-11-08 14:12:17 +09001578 /** {@hide} */
1579 @VisibleForTesting
1580 public int getProxyFileDescriptorMountPointId() {
1581 synchronized (mFuseAppLoopLock) {
1582 return mFuseAppLoop != null ? mFuseAppLoop.getMountPointId() : -1;
1583 }
1584 }
1585
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001586 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001587 * Return quota size in bytes for all cached data belonging to the calling
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001588 * app on the given storage volume.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001589 * <p>
1590 * If your app goes above this quota, your cached files will be some of the
1591 * first to be deleted when additional disk space is needed. Conversely, if
1592 * your app stays under this quota, your cached files will be some of the
1593 * last to be deleted when additional disk space is needed.
1594 * <p>
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001595 * This quota will change over time depending on how frequently the user
Jeff Sharkey60a82cd2017-04-18 18:19:16 -06001596 * interacts with your app, and depending on how much system-wide disk space
1597 * is used.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001598 * <p class="note">
1599 * Note: if your app uses the {@code android:sharedUserId} manifest feature,
1600 * then cached data for all packages in your shared UID is tracked together
1601 * as a single unit.
1602 * </p>
1603 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001604 * @param storageUuid the UUID of the storage volume that you're interested
1605 * in. The UUID for a specific path can be obtained using
1606 * {@link #getUuidForPath(File)}.
1607 * @throws IOException when the storage device isn't present, or when it
1608 * doesn't support cache quotas.
1609 * @see #getCacheSizeBytes(UUID)
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001610 */
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001611 @WorkerThread
1612 public @BytesLong long getCacheQuotaBytes(@NonNull UUID storageUuid) throws IOException {
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001613 try {
1614 final ApplicationInfo app = mContext.getApplicationInfo();
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001615 return mStorageManager.getCacheQuotaBytes(convert(storageUuid), app.uid);
1616 } catch (ParcelableException e) {
1617 e.maybeRethrow(IOException.class);
1618 throw new RuntimeException(e);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001619 } catch (RemoteException e) {
1620 throw e.rethrowFromSystemServer();
1621 }
1622 }
1623
1624 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001625 * Return total size in bytes of all cached data belonging to the calling
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001626 * app on the given storage volume.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001627 * <p>
1628 * Cached data tracked by this method always includes
1629 * {@link Context#getCacheDir()} and {@link Context#getCodeCacheDir()}, and
1630 * it also includes {@link Context#getExternalCacheDir()} if the primary
1631 * shared/external storage is hosted on the same storage device as your
1632 * private data.
1633 * <p class="note">
1634 * Note: if your app uses the {@code android:sharedUserId} manifest feature,
1635 * then cached data for all packages in your shared UID is tracked together
1636 * as a single unit.
1637 * </p>
1638 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001639 * @param storageUuid the UUID of the storage volume that you're interested
1640 * in. The UUID for a specific path can be obtained using
1641 * {@link #getUuidForPath(File)}.
1642 * @throws IOException when the storage device isn't present, or when it
1643 * doesn't support cache quotas.
1644 * @see #getCacheQuotaBytes(UUID)
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001645 */
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001646 @WorkerThread
1647 public @BytesLong long getCacheSizeBytes(@NonNull UUID storageUuid) throws IOException {
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001648 try {
1649 final ApplicationInfo app = mContext.getApplicationInfo();
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001650 return mStorageManager.getCacheSizeBytes(convert(storageUuid), app.uid);
1651 } catch (ParcelableException e) {
1652 e.maybeRethrow(IOException.class);
1653 throw new RuntimeException(e);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001654 } catch (RemoteException e) {
1655 throw e.rethrowFromSystemServer();
1656 }
1657 }
1658
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001659 /**
1660 * Flag indicating that a disk space allocation request should operate in an
1661 * aggressive mode. This flag should only be rarely used in situations that
1662 * are critical to system health or security.
1663 * <p>
1664 * When set, the system is more aggressive about the data that it considers
1665 * for possible deletion when allocating disk space.
1666 * <p class="note">
1667 * Note: your app must hold the
1668 * {@link android.Manifest.permission#ALLOCATE_AGGRESSIVE} permission for
1669 * this flag to take effect.
1670 * </p>
1671 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001672 * @see #getAllocatableBytes(UUID, int)
1673 * @see #allocateBytes(UUID, long, int)
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001674 * @see #allocateBytes(FileDescriptor, long, int)
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001675 * @hide
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001676 */
1677 @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE)
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001678 @SystemApi
Jeff Sharkeyddff8072017-05-26 13:10:46 -06001679 public static final int FLAG_ALLOCATE_AGGRESSIVE = 1 << 0;
1680
1681 /**
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001682 * Flag indicating that a disk space allocation request should be allowed to
1683 * clear up to all reserved disk space.
Jeff Sharkeyddff8072017-05-26 13:10:46 -06001684 *
1685 * @hide
1686 */
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001687 public static final int FLAG_ALLOCATE_DEFY_ALL_RESERVED = 1 << 1;
1688
1689 /**
1690 * Flag indicating that a disk space allocation request should be allowed to
1691 * clear up to half of all reserved disk space.
1692 *
1693 * @hide
1694 */
1695 public static final int FLAG_ALLOCATE_DEFY_HALF_RESERVED = 1 << 2;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001696
1697 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -07001698 @IntDef(flag = true, prefix = { "FLAG_ALLOCATE_" }, value = {
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001699 FLAG_ALLOCATE_AGGRESSIVE,
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001700 FLAG_ALLOCATE_DEFY_ALL_RESERVED,
1701 FLAG_ALLOCATE_DEFY_HALF_RESERVED,
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001702 })
1703 @Retention(RetentionPolicy.SOURCE)
1704 public @interface AllocateFlags {}
1705
1706 /**
1707 * Return the maximum number of new bytes that your app can allocate for
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001708 * itself on the given storage volume. This value is typically larger than
1709 * {@link File#getUsableSpace()}, since the system may be willing to delete
1710 * cached files to satisfy an allocation request. You can then allocate
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001711 * space for yourself using {@link #allocateBytes(UUID, long)} or
1712 * {@link #allocateBytes(FileDescriptor, long)}.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001713 * <p>
1714 * This method is best used as a pre-flight check, such as deciding if there
1715 * is enough space to store an entire music album before you allocate space
1716 * for each audio file in the album. Attempts to allocate disk space beyond
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001717 * the returned value will fail.
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001718 * <p>
1719 * If the returned value is not large enough for the data you'd like to
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001720 * persist, you can launch {@link #ACTION_MANAGE_STORAGE} with the
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001721 * {@link #EXTRA_UUID} and {@link #EXTRA_REQUESTED_BYTES} options to help
1722 * involve the user in freeing up disk space.
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001723 * <p>
1724 * If you're progressively allocating an unbounded amount of storage space
1725 * (such as when recording a video) you should avoid calling this method
1726 * more than once every 30 seconds.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001727 * <p class="note">
1728 * Note: if your app uses the {@code android:sharedUserId} manifest feature,
1729 * then allocatable space for all packages in your shared UID is tracked
1730 * together as a single unit.
1731 * </p>
1732 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001733 * @param storageUuid the UUID of the storage volume where you're
1734 * considering allocating disk space, since allocatable space can
1735 * vary widely depending on the underlying storage device. The
1736 * UUID for a specific path can be obtained using
1737 * {@link #getUuidForPath(File)}.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001738 * @return the maximum number of new bytes that the calling app can allocate
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001739 * using {@link #allocateBytes(UUID, long)} or
1740 * {@link #allocateBytes(FileDescriptor, long)}.
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001741 * @throws IOException when the storage device isn't present, or when it
1742 * doesn't support allocating space.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001743 */
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001744 @WorkerThread
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001745 public @BytesLong long getAllocatableBytes(@NonNull UUID storageUuid)
1746 throws IOException {
1747 return getAllocatableBytes(storageUuid, 0);
1748 }
1749
1750 /** @hide */
1751 @SystemApi
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001752 @WorkerThread
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -06001753 @SuppressLint("Doclava125")
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001754 public long getAllocatableBytes(@NonNull UUID storageUuid,
1755 @RequiresPermission @AllocateFlags int flags) throws IOException {
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001756 try {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001757 return mStorageManager.getAllocatableBytes(convert(storageUuid), flags,
1758 mContext.getOpPackageName());
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001759 } catch (ParcelableException e) {
1760 e.maybeRethrow(IOException.class);
1761 throw new RuntimeException(e);
1762 } catch (RemoteException e) {
1763 throw e.rethrowFromSystemServer();
1764 }
1765 }
1766
1767 /**
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001768 * Allocate the requested number of bytes for your application to use on the
1769 * given storage volume. This will cause the system to delete any cached
1770 * files necessary to satisfy your request.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001771 * <p>
1772 * Attempts to allocate disk space beyond the value returned by
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001773 * {@link #getAllocatableBytes(UUID)} will fail.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001774 * <p>
1775 * Since multiple apps can be running simultaneously, this method may be
1776 * subject to race conditions. If possible, consider using
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001777 * {@link #allocateBytes(FileDescriptor, long)} which will guarantee
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001778 * that bytes are allocated to an opened file.
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001779 * <p>
1780 * If you're progressively allocating an unbounded amount of storage space
1781 * (such as when recording a video) you should avoid calling this method
1782 * more than once every 60 seconds.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001783 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001784 * @param storageUuid the UUID of the storage volume where you'd like to
1785 * allocate disk space. The UUID for a specific path can be
1786 * obtained using {@link #getUuidForPath(File)}.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001787 * @param bytes the number of bytes to allocate.
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001788 * @throws IOException when the storage device isn't present, or when it
1789 * doesn't support allocating space, or if the device had
1790 * trouble allocating the requested space.
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001791 * @see #getAllocatableBytes(UUID)
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001792 */
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001793 @WorkerThread
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001794 public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes)
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001795 throws IOException {
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001796 allocateBytes(storageUuid, bytes, 0);
1797 }
1798
1799 /** @hide */
1800 @SystemApi
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001801 @WorkerThread
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -06001802 @SuppressLint("Doclava125")
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001803 public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes,
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001804 @RequiresPermission @AllocateFlags int flags) throws IOException {
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001805 try {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001806 mStorageManager.allocateBytes(convert(storageUuid), bytes, flags,
1807 mContext.getOpPackageName());
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001808 } catch (ParcelableException e) {
1809 e.maybeRethrow(IOException.class);
1810 } catch (RemoteException e) {
1811 throw e.rethrowFromSystemServer();
1812 }
1813 }
1814
1815 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001816 * Allocate the requested number of bytes for your application to use in the
1817 * given open file. This will cause the system to delete any cached files
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001818 * necessary to satisfy your request.
1819 * <p>
1820 * Attempts to allocate disk space beyond the value returned by
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001821 * {@link #getAllocatableBytes(UUID)} will fail.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001822 * <p>
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001823 * This method guarantees that bytes have been allocated to the opened file,
1824 * otherwise it will throw if fast allocation is not possible. Fast
1825 * allocation is typically only supported in private app data directories,
1826 * and on shared/external storage devices which are emulated.
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001827 * <p>
1828 * If you're progressively allocating an unbounded amount of storage space
1829 * (such as when recording a video) you should avoid calling this method
1830 * more than once every 60 seconds.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001831 *
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001832 * @param fd the open file that you'd like to allocate disk space for.
1833 * @param bytes the number of bytes to allocate. This is the desired final
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001834 * size of the open file. If the open file is smaller than this
1835 * requested size, it will be extended without modifying any
1836 * existing contents. If the open file is larger than this
1837 * requested size, it will be truncated.
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001838 * @throws IOException when the storage device isn't present, or when it
1839 * doesn't support allocating space, or if the device had
1840 * trouble allocating the requested space.
1841 * @see #getAllocatableBytes(UUID, int)
Jeff Sharkey4233f032017-07-15 12:58:38 -06001842 * @see #isAllocationSupported(FileDescriptor)
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001843 * @see Environment#isExternalStorageEmulated(File)
1844 */
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001845 @WorkerThread
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001846 public void allocateBytes(FileDescriptor fd, @BytesLong long bytes) throws IOException {
1847 allocateBytes(fd, bytes, 0);
1848 }
1849
1850 /** @hide */
1851 @SystemApi
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001852 @WorkerThread
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -06001853 @SuppressLint("Doclava125")
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001854 public void allocateBytes(FileDescriptor fd, @BytesLong long bytes,
1855 @RequiresPermission @AllocateFlags int flags) throws IOException {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001856 final File file = ParcelFileDescriptor.getFile(fd);
Jeff Sharkey4233f032017-07-15 12:58:38 -06001857 final UUID uuid = getUuidForPath(file);
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001858 for (int i = 0; i < 3; i++) {
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001859 try {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001860 final long haveBytes = Os.fstat(fd).st_blocks * 512;
1861 final long needBytes = bytes - haveBytes;
1862
1863 if (needBytes > 0) {
Jeff Sharkey4233f032017-07-15 12:58:38 -06001864 allocateBytes(uuid, needBytes, flags);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001865 }
1866
Jeff Sharkey4233f032017-07-15 12:58:38 -06001867 try {
1868 Os.posix_fallocate(fd, 0, bytes);
1869 return;
1870 } catch (ErrnoException e) {
1871 if (e.errno == OsConstants.ENOSYS || e.errno == OsConstants.ENOTSUP) {
1872 Log.w(TAG, "fallocate() not supported; falling back to ftruncate()");
1873 Os.ftruncate(fd, bytes);
1874 return;
1875 } else {
1876 throw e;
1877 }
1878 }
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001879 } catch (ErrnoException e) {
1880 if (e.errno == OsConstants.ENOSPC) {
1881 Log.w(TAG, "Odd, not enough space; let's try again?");
1882 continue;
1883 }
1884 throw e.rethrowAsIOException();
1885 }
1886 }
1887 throw new IOException(
1888 "Well this is embarassing; we can't allocate " + bytes + " for " + file);
1889 }
1890
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06001891 private static final String XATTR_CACHE_GROUP = "user.cache_group";
Jeff Sharkey458428e2017-02-22 11:47:15 -07001892 private static final String XATTR_CACHE_TOMBSTONE = "user.cache_tombstone";
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001893
1894 /** {@hide} */
1895 private static void setCacheBehavior(File path, String name, boolean enabled)
1896 throws IOException {
1897 if (!path.isDirectory()) {
1898 throw new IOException("Cache behavior can only be set on directories");
1899 }
1900 if (enabled) {
1901 try {
1902 Os.setxattr(path.getAbsolutePath(), name,
1903 "1".getBytes(StandardCharsets.UTF_8), 0);
1904 } catch (ErrnoException e) {
1905 throw e.rethrowAsIOException();
1906 }
1907 } else {
1908 try {
1909 Os.removexattr(path.getAbsolutePath(), name);
1910 } catch (ErrnoException e) {
1911 if (e.errno != OsConstants.ENODATA) {
1912 throw e.rethrowAsIOException();
1913 }
1914 }
1915 }
1916 }
1917
1918 /** {@hide} */
1919 private static boolean isCacheBehavior(File path, String name) throws IOException {
1920 try {
1921 Os.getxattr(path.getAbsolutePath(), name);
1922 return true;
1923 } catch (ErrnoException e) {
1924 if (e.errno != OsConstants.ENODATA) {
1925 throw e.rethrowAsIOException();
1926 } else {
1927 return false;
1928 }
1929 }
1930 }
1931
1932 /**
1933 * Enable or disable special cache behavior that treats this directory and
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06001934 * its contents as an entire group.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001935 * <p>
1936 * When enabled and this directory is considered for automatic deletion by
1937 * the OS, all contained files will either be deleted together, or not at
1938 * all. This is useful when you have a directory that contains several
1939 * related metadata files that depend on each other, such as movie file and
1940 * a subtitle file.
1941 * <p>
1942 * When enabled, the <em>newest</em> {@link File#lastModified()} value of
1943 * any contained files is considered the modified time of the entire
1944 * directory.
1945 * <p>
1946 * This behavior can only be set on a directory, and it applies recursively
1947 * to all contained files and directories.
1948 */
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06001949 public void setCacheBehaviorGroup(File path, boolean group) throws IOException {
1950 setCacheBehavior(path, XATTR_CACHE_GROUP, group);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001951 }
1952
1953 /**
1954 * Read the current value set by
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06001955 * {@link #setCacheBehaviorGroup(File, boolean)}.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001956 */
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06001957 public boolean isCacheBehaviorGroup(File path) throws IOException {
1958 return isCacheBehavior(path, XATTR_CACHE_GROUP);
1959 }
1960
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001961 /**
1962 * Enable or disable special cache behavior that leaves deleted cache files
1963 * intact as tombstones.
1964 * <p>
1965 * When enabled and a file contained in this directory is automatically
1966 * deleted by the OS, the file will be truncated to have a length of 0 bytes
1967 * instead of being fully deleted. This is useful if you need to distinguish
1968 * between a file that was deleted versus one that never existed.
1969 * <p>
1970 * This behavior can only be set on a directory, and it applies recursively
1971 * to all contained files and directories.
1972 * <p class="note">
1973 * Note: this behavior is ignored completely if the user explicitly requests
1974 * that all cached data be cleared.
1975 * </p>
1976 */
1977 public void setCacheBehaviorTombstone(File path, boolean tombstone) throws IOException {
Jeff Sharkey458428e2017-02-22 11:47:15 -07001978 setCacheBehavior(path, XATTR_CACHE_TOMBSTONE, tombstone);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001979 }
1980
1981 /**
1982 * Read the current value set by
1983 * {@link #setCacheBehaviorTombstone(File, boolean)}.
1984 */
1985 public boolean isCacheBehaviorTombstone(File path) throws IOException {
Jeff Sharkey458428e2017-02-22 11:47:15 -07001986 return isCacheBehavior(path, XATTR_CACHE_TOMBSTONE);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001987 }
1988
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001989 /** {@hide} */
1990 public static UUID convert(String uuid) {
1991 if (Objects.equals(uuid, UUID_PRIVATE_INTERNAL)) {
1992 return UUID_DEFAULT;
1993 } else if (Objects.equals(uuid, UUID_PRIMARY_PHYSICAL)) {
1994 return UUID_PRIMARY_PHYSICAL_;
1995 } else if (Objects.equals(uuid, UUID_SYSTEM)) {
1996 return UUID_SYSTEM_;
1997 } else {
1998 return UUID.fromString(uuid);
1999 }
2000 }
2001
2002 /** {@hide} */
2003 public static String convert(UUID storageUuid) {
2004 if (UUID_DEFAULT.equals(storageUuid)) {
2005 return UUID_PRIVATE_INTERNAL;
2006 } else if (UUID_PRIMARY_PHYSICAL_.equals(storageUuid)) {
2007 return UUID_PRIMARY_PHYSICAL;
2008 } else if (UUID_SYSTEM_.equals(storageUuid)) {
2009 return UUID_SYSTEM;
2010 } else {
2011 return storageUuid.toString();
2012 }
2013 }
2014
Daichi Hirono9fb00182016-11-08 14:12:17 +09002015 private final Object mFuseAppLoopLock = new Object();
2016
2017 @GuardedBy("mFuseAppLoopLock")
2018 private @Nullable FuseAppLoop mFuseAppLoop = null;
2019
Paul Lawrencee8fdc542014-05-28 07:14:17 -07002020 /// Consts to match the password types in cryptfs.h
2021 /** @hide */
Jeff Sharkey43e12112017-09-12 16:31:45 -06002022 public static final int CRYPT_TYPE_PASSWORD = IVold.PASSWORD_TYPE_PASSWORD;
Paul Lawrencee8fdc542014-05-28 07:14:17 -07002023 /** @hide */
Jeff Sharkey43e12112017-09-12 16:31:45 -06002024 public static final int CRYPT_TYPE_DEFAULT = IVold.PASSWORD_TYPE_DEFAULT;
Paul Lawrencee8fdc542014-05-28 07:14:17 -07002025 /** @hide */
Jeff Sharkey43e12112017-09-12 16:31:45 -06002026 public static final int CRYPT_TYPE_PATTERN = IVold.PASSWORD_TYPE_PATTERN;
Paul Lawrencee8fdc542014-05-28 07:14:17 -07002027 /** @hide */
Jeff Sharkey43e12112017-09-12 16:31:45 -06002028 public static final int CRYPT_TYPE_PIN = IVold.PASSWORD_TYPE_PIN;
Elliott Hughesf839b4f2014-09-26 12:30:47 -07002029
Sudheer Shanka2250d562016-11-07 15:41:02 -08002030 // Constants for the data available via StorageManagerService.getField.
Elliott Hughesf839b4f2014-09-26 12:30:47 -07002031 /** @hide */
2032 public static final String SYSTEM_LOCALE_KEY = "SystemLocale";
2033 /** @hide */
2034 public static final String OWNER_INFO_KEY = "OwnerInfo";
2035 /** @hide */
2036 public static final String PATTERN_VISIBLE_KEY = "PatternVisible";
Paul Lawrenced8fdb332015-05-18 13:26:11 -07002037 /** @hide */
2038 public static final String PASSWORD_VISIBLE_KEY = "PasswordVisible";
San Mehatb1043402010-02-05 08:26:50 -08002039}