blob: 4796712f2d987a98a4f776da088da31a6ecfdd69 [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 Sharkeyd5d5e922017-02-21 10:51:23 -070019import static android.net.TrafficStats.GB_IN_BYTES;
Jeff Sharkeybe722152013-02-15 16:56:38 -080020import static android.net.TrafficStats.MB_IN_BYTES;
21
Jeff Sharkeya4d34d92017-04-27 11:21:41 -060022import android.annotation.BytesLong;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -070023import android.annotation.IntDef;
Jeff Sharkey48877892015-03-18 11:27:19 -070024import android.annotation.NonNull;
25import android.annotation.Nullable;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -070026import android.annotation.RequiresPermission;
Daniel Nishi690346b2016-06-17 10:21:48 -070027import android.annotation.SdkConstant;
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -060028import android.annotation.SuppressLint;
Jeff Sharkeya4d34d92017-04-27 11:21:41 -060029import android.annotation.SystemApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060030import android.annotation.SystemService;
Jeff Sharkeya4d34d92017-04-27 11:21:41 -060031import android.annotation.WorkerThread;
Jeff Sharkeyb31afd22017-06-12 14:17:10 -060032import android.app.Activity;
Svet Ganov6ee871e2015-07-10 14:29:33 -070033import android.app.ActivityThread;
Jeff Sharkeybe722152013-02-15 16:56:38 -080034import android.content.ContentResolver;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070035import android.content.Context;
Jeff Sharkeya4d34d92017-04-27 11:21:41 -060036import android.content.Intent;
Jeff Sharkey9bed0702017-01-23 20:37:05 -070037import android.content.pm.ApplicationInfo;
Jeff Sharkey275e3e42015-04-24 16:10:32 -070038import android.content.pm.IPackageMoveObserver;
39import android.content.pm.PackageManager;
Jeff Sharkeyce18c812016-04-27 16:00:41 -060040import android.os.Binder;
Mike Lockwoodcba928c2011-08-17 15:58:52 -070041import android.os.Environment;
Jeff Sharkey48877892015-03-18 11:27:19 -070042import android.os.FileUtils;
San Mehatb1043402010-02-05 08:26:50 -080043import android.os.Handler;
Jeff Sharkey41cd6812017-09-11 10:32:17 -060044import android.os.IVold;
Jeff Sharkey7e19f532017-11-06 13:54:11 -070045import android.os.IVoldTaskListener;
Kenny Roota02b8b02010-08-05 16:14:17 -070046import android.os.Looper;
San Mehatb1043402010-02-05 08:26:50 -080047import android.os.Message;
Daichi Hirono9e8d9e22015-11-13 14:37:00 +090048import android.os.ParcelFileDescriptor;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -070049import android.os.ParcelableException;
Jeff Sharkey7e19f532017-11-06 13:54:11 -070050import android.os.PersistableBundle;
Jeff Sharkey9bed0702017-01-23 20:37:05 -070051import android.os.ProxyFileDescriptorCallback;
Kenny Roota02b8b02010-08-05 16:14:17 -070052import android.os.RemoteException;
San Mehatb1043402010-02-05 08:26:50 -080053import android.os.ServiceManager;
Jeff Sharkey49ca5292016-05-10 12:54:45 -060054import android.os.ServiceManager.ServiceNotFoundException;
Jeff Sharkeyba512352015-11-12 20:17:45 -080055import android.os.SystemProperties;
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -060056import android.os.UserHandle;
Jeff Sharkeybe722152013-02-15 16:56:38 -080057import android.provider.Settings;
Jeff Sharkey9bed0702017-01-23 20:37:05 -070058import android.system.ErrnoException;
59import android.system.Os;
60import android.system.OsConstants;
Jeff Sharkey59d577a2015-04-11 21:27:21 -070061import android.text.TextUtils;
San Mehatb1043402010-02-05 08:26:50 -080062import android.util.Log;
Felipe Leme281389a2016-10-10 17:12:20 -070063import android.util.Pair;
Jeff Sharkeyb42d6942015-04-28 22:25:26 -070064import android.util.Slog;
Kenny Rootaf9d6672010-10-08 09:21:39 -070065import android.util.SparseArray;
Jeff Sharkey9bed0702017-01-23 20:37:05 -070066
Daichi Hirono9fb00182016-11-08 14:12:17 +090067import com.android.internal.annotations.GuardedBy;
68import com.android.internal.annotations.VisibleForTesting;
Daichi Hironod61817e2017-02-13 10:37:11 +090069import com.android.internal.logging.MetricsLogger;
Daichi Hirono9fb00182016-11-08 14:12:17 +090070import com.android.internal.os.AppFuseMount;
71import com.android.internal.os.FuseAppLoop;
Daichi Hirono812c95d2017-02-08 16:20:20 +090072import com.android.internal.os.FuseUnavailableMountException;
John Reckaa67f682016-09-20 14:24:21 -070073import com.android.internal.os.RoSystemProperties;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070074import com.android.internal.os.SomeArgs;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -070075import com.android.internal.util.Preconditions;
76
77import java.io.File;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -070078import java.io.FileDescriptor;
Jeff Sharkey789a8fc2017-04-16 13:18:35 -060079import java.io.FileNotFoundException;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -070080import java.io.IOException;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -070081import java.lang.annotation.Retention;
82import java.lang.annotation.RetentionPolicy;
Kenny Root05105f72010-09-22 17:29:43 -070083import java.lang.ref.WeakReference;
Jeff Sharkey9bed0702017-01-23 20:37:05 -070084import java.nio.charset.StandardCharsets;
San Mehatb1043402010-02-05 08:26:50 -080085import java.util.ArrayList;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070086import java.util.Arrays;
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -060087import java.util.Collections;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070088import java.util.Iterator;
Kenny Root05105f72010-09-22 17:29:43 -070089import java.util.List;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070090import java.util.Objects;
Jeff Sharkey789a8fc2017-04-16 13:18:35 -060091import java.util.UUID;
Jeff Sharkey7e19f532017-11-06 13:54:11 -070092import java.util.concurrent.CompletableFuture;
Daichi Hirono9fb00182016-11-08 14:12:17 +090093import java.util.concurrent.ThreadFactory;
Jeff Sharkey7e19f532017-11-06 13:54:11 -070094import java.util.concurrent.TimeUnit;
Kenny Rootaf9d6672010-10-08 09:21:39 -070095import java.util.concurrent.atomic.AtomicInteger;
San Mehatb1043402010-02-05 08:26:50 -080096
97/**
Kenny Root05105f72010-09-22 17:29:43 -070098 * StorageManager is the interface to the systems storage service. The storage
99 * manager handles storage-related items such as Opaque Binary Blobs (OBBs).
100 * <p>
101 * OBBs contain a filesystem that maybe be encrypted on disk and mounted
102 * on-demand from an application. OBBs are a good way of providing large amounts
103 * of binary assets without packaging them into APKs as they may be multiple
104 * gigabytes in size. However, due to their size, they're most likely stored in
105 * a shared storage pool accessible from all programs. The system does not
106 * guarantee the security of the OBB file itself: if any program modifies the
107 * OBB, there is no guarantee that a read from that OBB will produce the
108 * expected output.
San Mehatb1043402010-02-05 08:26:50 -0800109 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600110@SystemService(Context.STORAGE_SERVICE)
Jeff Sharkeybe722152013-02-15 16:56:38 -0800111public class StorageManager {
San Mehatb1043402010-02-05 08:26:50 -0800112 private static final String TAG = "StorageManager";
113
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700114 /** {@hide} */
115 public static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical";
Jeff Sharkey74acbbb2015-04-21 12:14:03 -0700116 /** {@hide} */
Jeff Sharkey0d838a02015-05-13 13:54:30 -0700117 public static final String PROP_HAS_ADOPTABLE = "vold.has_adoptable";
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 Sharkeya65e6492017-06-21 13:45:11 -0600126 /** {@hide} */
127 public static final String PROP_ADOPTABLE_FBE = "persist.sys.adoptable_fbe";
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700128
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700129 /** {@hide} */
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700130 public static final String UUID_PRIVATE_INTERNAL = null;
131 /** {@hide} */
132 public static final String UUID_PRIMARY_PHYSICAL = "primary_physical";
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600133 /** {@hide} */
134 public static final String UUID_SYSTEM = "system";
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700135
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600136 // NOTE: UUID constants below are namespaced
137 // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad default
138 // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad primary_physical
139 // uuid -v5 ad99aa3d-308e-4191-a200-ebcab371c0ad system
Daniel Nishi690346b2016-06-17 10:21:48 -0700140
141 /**
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600142 * UUID representing the default internal storage of this device which
143 * provides {@link Environment#getDataDirectory()}.
Daniel Nishi690346b2016-06-17 10:21:48 -0700144 * <p>
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600145 * This value is constant across all devices and it will never change, and
146 * thus it cannot be used to uniquely identify a particular physical device.
147 *
148 * @see #getUuidForPath(File)
Jeff Sharkeya4d34d92017-04-27 11:21:41 -0600149 * @see ApplicationInfo#storageUuid
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600150 */
151 public static final UUID UUID_DEFAULT = UUID
152 .fromString("41217664-9172-527a-b3d5-edabb50a7d69");
153
154 /** {@hide} */
155 public static final UUID UUID_PRIMARY_PHYSICAL_ = UUID
156 .fromString("0f95a519-dae7-5abf-9519-fbd6209e05fd");
157
158 /** {@hide} */
159 public static final UUID UUID_SYSTEM_ = UUID
160 .fromString("5d258386-e60d-59e3-826d-0089cdd42cc0");
161
162 /**
163 * Activity Action: Allows the user to manage their storage. This activity
164 * provides the ability to free up space on the device by deleting data such
165 * as apps.
Daniel Nishi690346b2016-06-17 10:21:48 -0700166 * <p>
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600167 * If the sending application has a specific storage device or allocation
168 * size in mind, they can optionally define {@link #EXTRA_UUID} or
169 * {@link #EXTRA_REQUESTED_BYTES}, respectively.
Jeff Sharkeyb31afd22017-06-12 14:17:10 -0600170 * <p>
171 * This intent should be launched using
172 * {@link Activity#startActivityForResult(Intent, int)} so that the user
173 * knows which app is requesting the storage space. The returned result will
174 * be {@link Activity#RESULT_OK} if the requested space was made available,
175 * or {@link Activity#RESULT_CANCELED} otherwise.
Daniel Nishi690346b2016-06-17 10:21:48 -0700176 */
177 @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600178 public static final String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
179
180 /**
181 * Extra {@link UUID} used to indicate the storage volume where an
182 * application is interested in allocating or managing disk space.
183 *
184 * @see #ACTION_MANAGE_STORAGE
185 * @see #UUID_DEFAULT
186 * @see #getUuidForPath(File)
Jeff Sharkeya4d34d92017-04-27 11:21:41 -0600187 * @see Intent#putExtra(String, java.io.Serializable)
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600188 */
189 public static final String EXTRA_UUID = "android.os.storage.extra.UUID";
190
191 /**
192 * Extra used to indicate the total size (in bytes) that an application is
193 * interested in allocating.
194 * <p>
195 * When defined, the management UI will help guide the user to free up
196 * enough disk space to reach this requested value.
197 *
198 * @see #ACTION_MANAGE_STORAGE
199 */
200 public static final String EXTRA_REQUESTED_BYTES = "android.os.storage.extra.REQUESTED_BYTES";
Daniel Nishi690346b2016-06-17 10:21:48 -0700201
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700202 /** {@hide} */
203 public static final int DEBUG_FORCE_ADOPTABLE = 1 << 0;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800204 /** {@hide} */
205 public static final int DEBUG_EMULATE_FBE = 1 << 1;
Jeff Sharkey33dd1562016-04-07 11:05:33 -0600206 /** {@hide} */
207 public static final int DEBUG_SDCARDFS_FORCE_ON = 1 << 2;
208 /** {@hide} */
209 public static final int DEBUG_SDCARDFS_FORCE_OFF = 1 << 3;
Jeff Sharkeye53e2d92017-03-25 23:14:06 -0600210 /** {@hide} */
211 public static final int DEBUG_VIRTUAL_DISK = 1 << 4;
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700212
Jeff Sharkey47f71082016-02-01 17:03:54 -0700213 // NOTE: keep in sync with installd
Jeff Sharkey46349872015-07-28 10:49:47 -0700214 /** {@hide} */
Jeff Sharkey47f71082016-02-01 17:03:54 -0700215 public static final int FLAG_STORAGE_DE = 1 << 0;
216 /** {@hide} */
217 public static final int FLAG_STORAGE_CE = 1 << 1;
218
219 /** {@hide} */
220 public static final int FLAG_FOR_WRITE = 1 << 8;
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -0600221 /** {@hide} */
222 public static final int FLAG_REAL_STATE = 1 << 9;
223 /** {@hide} */
224 public static final int FLAG_INCLUDE_INVISIBLE = 1 << 10;
Jeff Sharkey46349872015-07-28 10:49:47 -0700225
Jeff Sharkey31d0b702016-11-21 14:16:53 -0700226 /** {@hide} */
Jeff Sharkey41cd6812017-09-11 10:32:17 -0600227 public static final int FSTRIM_FLAG_DEEP = IVold.FSTRIM_FLAG_DEEP_TRIM;
Jeff Sharkey31d0b702016-11-21 14:16:53 -0700228
Sudheer Shankaf7341142016-10-18 17:15:18 -0700229 /** @hide The volume is not encrypted. */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600230 public static final int ENCRYPTION_STATE_NONE =
231 IVold.ENCRYPTION_STATE_NONE;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700232
233 /** @hide The volume has been encrypted succesfully. */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600234 public static final int ENCRYPTION_STATE_OK =
235 IVold.ENCRYPTION_STATE_OK;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700236
Jeff Sharkey43e12112017-09-12 16:31:45 -0600237 /** @hide The volume is in a bad state. */
238 public static final int ENCRYPTION_STATE_ERROR_UNKNOWN =
239 IVold.ENCRYPTION_STATE_ERROR_UNKNOWN;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700240
241 /** @hide Encryption is incomplete */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600242 public static final int ENCRYPTION_STATE_ERROR_INCOMPLETE =
243 IVold.ENCRYPTION_STATE_ERROR_INCOMPLETE;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700244
245 /** @hide Encryption is incomplete and irrecoverable */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600246 public static final int ENCRYPTION_STATE_ERROR_INCONSISTENT =
247 IVold.ENCRYPTION_STATE_ERROR_INCONSISTENT;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700248
249 /** @hide Underlying data is corrupt */
Jeff Sharkey43e12112017-09-12 16:31:45 -0600250 public static final int ENCRYPTION_STATE_ERROR_CORRUPT =
251 IVold.ENCRYPTION_STATE_ERROR_CORRUPT;
Sudheer Shankaf7341142016-10-18 17:15:18 -0700252
Sudheer Shanka2250d562016-11-07 15:41:02 -0800253 private static volatile IStorageManager sStorageManager = null;
Felipe Leme179923a2016-07-19 09:33:31 -0700254
Jeff Sharkey48877892015-03-18 11:27:19 -0700255 private final Context mContext;
Jeff Sharkeybe722152013-02-15 16:56:38 -0800256 private final ContentResolver mResolver;
257
Sudheer Shanka2250d562016-11-07 15:41:02 -0800258 private final IStorageManager mStorageManager;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700259 private final Looper mLooper;
260 private final AtomicInteger mNextNonce = new AtomicInteger(0);
San Mehatb1043402010-02-05 08:26:50 -0800261
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700262 private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>();
San Mehatb1043402010-02-05 08:26:50 -0800263
Sudheer Shanka2250d562016-11-07 15:41:02 -0800264 private static class StorageEventListenerDelegate extends IStorageEventListener.Stub implements
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700265 Handler.Callback {
266 private static final int MSG_STORAGE_STATE_CHANGED = 1;
267 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700268 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
269 private static final int MSG_VOLUME_FORGOTTEN = 4;
270 private static final int MSG_DISK_SCANNED = 5;
Makoto Onuki9dc575d2015-06-12 16:10:25 -0700271 private static final int MSG_DISK_DESTROYED = 6;
San Mehatb1043402010-02-05 08:26:50 -0800272
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700273 final StorageEventListener mCallback;
274 final Handler mHandler;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700275
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700276 public StorageEventListenerDelegate(StorageEventListener callback, Looper looper) {
277 mCallback = callback;
278 mHandler = new Handler(looper, this);
San Mehatb1043402010-02-05 08:26:50 -0800279 }
280
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700281 @Override
282 public boolean handleMessage(Message msg) {
283 final SomeArgs args = (SomeArgs) msg.obj;
284 switch (msg.what) {
285 case MSG_STORAGE_STATE_CHANGED:
286 mCallback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
287 (String) args.arg3);
288 args.recycle();
289 return true;
290 case MSG_VOLUME_STATE_CHANGED:
291 mCallback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
292 args.recycle();
293 return true;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700294 case MSG_VOLUME_RECORD_CHANGED:
295 mCallback.onVolumeRecordChanged((VolumeRecord) args.arg1);
296 args.recycle();
297 return true;
298 case MSG_VOLUME_FORGOTTEN:
299 mCallback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700300 args.recycle();
301 return true;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700302 case MSG_DISK_SCANNED:
303 mCallback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700304 args.recycle();
305 return true;
Makoto Onuki9dc575d2015-06-12 16:10:25 -0700306 case MSG_DISK_DESTROYED:
307 mCallback.onDiskDestroyed((DiskInfo) args.arg1);
308 args.recycle();
309 return true;
San Mehatb1043402010-02-05 08:26:50 -0800310 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700311 args.recycle();
312 return false;
313 }
314
315 @Override
316 public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException {
317 // Ignored
318 }
319
320 @Override
321 public void onStorageStateChanged(String path, String oldState, String newState) {
322 final SomeArgs args = SomeArgs.obtain();
323 args.arg1 = path;
324 args.arg2 = oldState;
325 args.arg3 = newState;
326 mHandler.obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
327 }
328
329 @Override
330 public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
331 final SomeArgs args = SomeArgs.obtain();
332 args.arg1 = vol;
333 args.argi2 = oldState;
334 args.argi3 = newState;
335 mHandler.obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
San Mehatb1043402010-02-05 08:26:50 -0800336 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700337
338 @Override
Jeff Sharkey50a05452015-04-29 11:24:52 -0700339 public void onVolumeRecordChanged(VolumeRecord rec) {
340 final SomeArgs args = SomeArgs.obtain();
341 args.arg1 = rec;
342 mHandler.obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
343 }
344
345 @Override
346 public void onVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700347 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700348 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700349 mHandler.obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700350 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700351
352 @Override
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700353 public void onDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700354 final SomeArgs args = SomeArgs.obtain();
355 args.arg1 = disk;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700356 args.argi2 = volumeCount;
357 mHandler.obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700358 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -0700359
360 @Override
361 public void onDiskDestroyed(DiskInfo disk) throws RemoteException {
362 final SomeArgs args = SomeArgs.obtain();
363 args.arg1 = disk;
364 mHandler.obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
365 }
San Mehatb1043402010-02-05 08:26:50 -0800366 }
367
368 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700369 * Binder listener for OBB action results.
370 */
Kenny Root05105f72010-09-22 17:29:43 -0700371 private final ObbActionListener mObbActionListener = new ObbActionListener();
372
373 private class ObbActionListener extends IObbActionListener.Stub {
Gilles Debunne37051cd2011-05-25 16:27:13 -0700374 @SuppressWarnings("hiding")
Kenny Rootaf9d6672010-10-08 09:21:39 -0700375 private SparseArray<ObbListenerDelegate> mListeners = new SparseArray<ObbListenerDelegate>();
Kenny Root05105f72010-09-22 17:29:43 -0700376
Kenny Roota02b8b02010-08-05 16:14:17 -0700377 @Override
Gilles Debunne37051cd2011-05-25 16:27:13 -0700378 public void onObbResult(String filename, int nonce, int status) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700379 final ObbListenerDelegate delegate;
Kenny Root05105f72010-09-22 17:29:43 -0700380 synchronized (mListeners) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700381 delegate = mListeners.get(nonce);
382 if (delegate != null) {
383 mListeners.remove(nonce);
Kenny Root05105f72010-09-22 17:29:43 -0700384 }
385 }
Kenny Rootaf9d6672010-10-08 09:21:39 -0700386
387 if (delegate != null) {
388 delegate.sendObbStateChanged(filename, status);
389 }
Kenny Root05105f72010-09-22 17:29:43 -0700390 }
391
Kenny Rootaf9d6672010-10-08 09:21:39 -0700392 public int addListener(OnObbStateChangeListener listener) {
393 final ObbListenerDelegate delegate = new ObbListenerDelegate(listener);
Kenny Root05105f72010-09-22 17:29:43 -0700394
395 synchronized (mListeners) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700396 mListeners.put(delegate.nonce, delegate);
Kenny Root05105f72010-09-22 17:29:43 -0700397 }
Kenny Rootaf9d6672010-10-08 09:21:39 -0700398
399 return delegate.nonce;
Kenny Root05105f72010-09-22 17:29:43 -0700400 }
401 }
402
Kenny Rootaf9d6672010-10-08 09:21:39 -0700403 private int getNextNonce() {
404 return mNextNonce.getAndIncrement();
405 }
406
Kenny Root05105f72010-09-22 17:29:43 -0700407 /**
408 * Private class containing sender and receiver code for StorageEvents.
409 */
410 private class ObbListenerDelegate {
411 private final WeakReference<OnObbStateChangeListener> mObbEventListenerRef;
412 private final Handler mHandler;
413
Kenny Rootaf9d6672010-10-08 09:21:39 -0700414 private final int nonce;
415
Kenny Root05105f72010-09-22 17:29:43 -0700416 ObbListenerDelegate(OnObbStateChangeListener listener) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700417 nonce = getNextNonce();
Kenny Root05105f72010-09-22 17:29:43 -0700418 mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700419 mHandler = new Handler(mLooper) {
Kenny Root05105f72010-09-22 17:29:43 -0700420 @Override
421 public void handleMessage(Message msg) {
Gilles Debunne37051cd2011-05-25 16:27:13 -0700422 final OnObbStateChangeListener changeListener = getListener();
423 if (changeListener == null) {
Kenny Root05105f72010-09-22 17:29:43 -0700424 return;
425 }
426
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700427 changeListener.onObbStateChange((String) msg.obj, msg.arg1);
Kenny Root05105f72010-09-22 17:29:43 -0700428 }
429 };
430 }
431
432 OnObbStateChangeListener getListener() {
433 if (mObbEventListenerRef == null) {
434 return null;
435 }
436 return mObbEventListenerRef.get();
437 }
438
Kenny Rootaf9d6672010-10-08 09:21:39 -0700439 void sendObbStateChanged(String path, int state) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700440 mHandler.obtainMessage(0, state, 0, path).sendToTarget();
San Mehatb1043402010-02-05 08:26:50 -0800441 }
442 }
443
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700444 /** {@hide} */
Jeff Sharkey50a05452015-04-29 11:24:52 -0700445 @Deprecated
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700446 public static StorageManager from(Context context) {
Jeff Sharkey50a05452015-04-29 11:24:52 -0700447 return context.getSystemService(StorageManager.class);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700448 }
449
San Mehatb1043402010-02-05 08:26:50 -0800450 /**
451 * Constructs a StorageManager object through which an application can
452 * can communicate with the systems mount service.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900453 *
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600454 * @param looper The {@link android.os.Looper} which events will be received on.
San Mehatb1043402010-02-05 08:26:50 -0800455 *
456 * <p>Applications can get instance of this class by calling
457 * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
458 * of {@link android.content.Context#STORAGE_SERVICE}.
459 *
460 * @hide
461 */
Jeff Sharkey49ca5292016-05-10 12:54:45 -0600462 public StorageManager(Context context, Looper looper) throws ServiceNotFoundException {
Jeff Sharkey48877892015-03-18 11:27:19 -0700463 mContext = context;
464 mResolver = context.getContentResolver();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700465 mLooper = looper;
Sudheer Shanka2250d562016-11-07 15:41:02 -0800466 mStorageManager = IStorageManager.Stub.asInterface(ServiceManager.getServiceOrThrow("mount"));
San Mehatb1043402010-02-05 08:26:50 -0800467 }
468
San Mehatb1043402010-02-05 08:26:50 -0800469 /**
470 * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}.
471 *
472 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
473 *
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800474 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800475 */
476 public void registerListener(StorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700477 synchronized (mDelegates) {
478 final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(listener,
479 mLooper);
480 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800481 mStorageManager.registerListener(delegate);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700482 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700483 throw e.rethrowFromSystemServer();
Chuanxia Dong6614bb62012-05-29 12:28:24 +0800484 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700485 mDelegates.add(delegate);
San Mehatb1043402010-02-05 08:26:50 -0800486 }
487 }
488
489 /**
490 * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}.
491 *
492 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
493 *
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800494 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800495 */
496 public void unregisterListener(StorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700497 synchronized (mDelegates) {
498 for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) {
499 final StorageEventListenerDelegate delegate = i.next();
500 if (delegate.mCallback == listener) {
501 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800502 mStorageManager.unregisterListener(delegate);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700503 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700504 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700505 }
506 i.remove();
507 }
508 }
San Mehatb1043402010-02-05 08:26:50 -0800509 }
San Mehatb1043402010-02-05 08:26:50 -0800510 }
511
512 /**
513 * Enables USB Mass Storage (UMS) on the device.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800514 *
515 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800516 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700517 @Deprecated
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800518 public void enableUsbMassStorage() {
San Mehatb1043402010-02-05 08:26:50 -0800519 }
520
521 /**
522 * Disables USB Mass Storage (UMS) on the device.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800523 *
524 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800525 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700526 @Deprecated
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800527 public void disableUsbMassStorage() {
San Mehatb1043402010-02-05 08:26:50 -0800528 }
529
530 /**
531 * Query if a USB Mass Storage (UMS) host is connected.
532 * @return true if UMS host is connected.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800533 *
534 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800535 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700536 @Deprecated
San Mehatb1043402010-02-05 08:26:50 -0800537 public boolean isUsbMassStorageConnected() {
San Mehatb1043402010-02-05 08:26:50 -0800538 return false;
539 }
540
541 /**
542 * Query if a USB Mass Storage (UMS) is enabled on the device.
543 * @return true if UMS host is enabled.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800544 *
545 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800546 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700547 @Deprecated
San Mehatb1043402010-02-05 08:26:50 -0800548 public boolean isUsbMassStorageEnabled() {
San Mehatb1043402010-02-05 08:26:50 -0800549 return false;
550 }
Kenny Root02c87302010-07-01 08:10:18 -0700551
552 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700553 * Mount an Opaque Binary Blob (OBB) file. If a <code>key</code> is
554 * specified, it is supplied to the mounting process to be used in any
555 * encryption used in the OBB.
556 * <p>
Kenny Root05105f72010-09-22 17:29:43 -0700557 * The OBB will remain mounted for as long as the StorageManager reference
558 * is held by the application. As soon as this reference is lost, the OBBs
Kenny Rootaf9d6672010-10-08 09:21:39 -0700559 * in use will be unmounted. The {@link OnObbStateChangeListener} registered
560 * with this call will receive the success or failure of this operation.
Kenny Root05105f72010-09-22 17:29:43 -0700561 * <p>
Kenny Roota02b8b02010-08-05 16:14:17 -0700562 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
563 * file matches a package ID that is owned by the calling program's UID.
Kenny Root05105f72010-09-22 17:29:43 -0700564 * That is, shared UID applications can attempt to mount any other
Kenny Roota02b8b02010-08-05 16:14:17 -0700565 * application's OBB that shares its UID.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900566 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700567 * @param rawPath the path to the OBB file
Kenny Root05105f72010-09-22 17:29:43 -0700568 * @param key secret used to encrypt the OBB; may be <code>null</code> if no
569 * encryption was used on the OBB.
Kenny Rootaf9d6672010-10-08 09:21:39 -0700570 * @param listener will receive the success or failure of the operation
Kenny Roota02b8b02010-08-05 16:14:17 -0700571 * @return whether the mount call was successfully queued or not
Kenny Root02c87302010-07-01 08:10:18 -0700572 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700573 public boolean mountObb(String rawPath, String key, OnObbStateChangeListener listener) {
574 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
575 Preconditions.checkNotNull(listener, "listener cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700576
Kenny Root02c87302010-07-01 08:10:18 -0700577 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700578 final String canonicalPath = new File(rawPath).getCanonicalPath();
Kenny Rootaf9d6672010-10-08 09:21:39 -0700579 final int nonce = mObbActionListener.addListener(listener);
Sudheer Shanka2250d562016-11-07 15:41:02 -0800580 mStorageManager.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce);
Kenny Roota02b8b02010-08-05 16:14:17 -0700581 return true;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700582 } catch (IOException e) {
583 throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e);
Kenny Root02c87302010-07-01 08:10:18 -0700584 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700585 throw e.rethrowFromSystemServer();
Kenny Root02c87302010-07-01 08:10:18 -0700586 }
Kenny Root02c87302010-07-01 08:10:18 -0700587 }
588
589 /**
Kenny Root05105f72010-09-22 17:29:43 -0700590 * Unmount an Opaque Binary Blob (OBB) file asynchronously. If the
591 * <code>force</code> flag is true, it will kill any application needed to
592 * unmount the given OBB (even the calling application).
593 * <p>
Kenny Rootaf9d6672010-10-08 09:21:39 -0700594 * The {@link OnObbStateChangeListener} registered with this call will
595 * receive the success or failure of this operation.
Kenny Roota02b8b02010-08-05 16:14:17 -0700596 * <p>
597 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
598 * file matches a package ID that is owned by the calling program's UID.
599 * That is, shared UID applications can obtain access to any other
600 * application's OBB that shares its UID.
Kenny Root02ca31f2010-08-12 07:36:02 -0700601 * <p>
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900602 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700603 * @param rawPath path to the OBB file
Kenny Roota02b8b02010-08-05 16:14:17 -0700604 * @param force whether to kill any programs using this in order to unmount
605 * it
Kenny Rootaf9d6672010-10-08 09:21:39 -0700606 * @param listener will receive the success or failure of the operation
Kenny Roota02b8b02010-08-05 16:14:17 -0700607 * @return whether the unmount call was successfully queued or not
Kenny Root02c87302010-07-01 08:10:18 -0700608 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700609 public boolean unmountObb(String rawPath, boolean force, OnObbStateChangeListener listener) {
610 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
611 Preconditions.checkNotNull(listener, "listener cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700612
Kenny Root02c87302010-07-01 08:10:18 -0700613 try {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700614 final int nonce = mObbActionListener.addListener(listener);
Sudheer Shanka2250d562016-11-07 15:41:02 -0800615 mStorageManager.unmountObb(rawPath, force, mObbActionListener, nonce);
Kenny Roota02b8b02010-08-05 16:14:17 -0700616 return true;
Kenny Root02c87302010-07-01 08:10:18 -0700617 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700618 throw e.rethrowFromSystemServer();
Kenny Root02c87302010-07-01 08:10:18 -0700619 }
Kenny Root02c87302010-07-01 08:10:18 -0700620 }
621
Kenny Roota02b8b02010-08-05 16:14:17 -0700622 /**
623 * Check whether an Opaque Binary Blob (OBB) is mounted or not.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900624 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700625 * @param rawPath path to OBB image
Kenny Roota02b8b02010-08-05 16:14:17 -0700626 * @return true if OBB is mounted; false if not mounted or on error
627 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700628 public boolean isObbMounted(String rawPath) {
629 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700630
Kenny Root02c87302010-07-01 08:10:18 -0700631 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800632 return mStorageManager.isObbMounted(rawPath);
Kenny Root02c87302010-07-01 08:10:18 -0700633 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700634 throw e.rethrowFromSystemServer();
Kenny Root02c87302010-07-01 08:10:18 -0700635 }
Kenny Root02c87302010-07-01 08:10:18 -0700636 }
637
638 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700639 * Check the mounted path of an Opaque Binary Blob (OBB) file. This will
640 * give you the path to where you can obtain access to the internals of the
641 * OBB.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900642 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700643 * @param rawPath path to OBB image
Kenny Roota02b8b02010-08-05 16:14:17 -0700644 * @return absolute path to mounted OBB image data or <code>null</code> if
645 * not mounted or exception encountered trying to read status
Kenny Root02c87302010-07-01 08:10:18 -0700646 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700647 public String getMountedObbPath(String rawPath) {
648 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700649
Kenny Root02c87302010-07-01 08:10:18 -0700650 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800651 return mStorageManager.getMountedObbPath(rawPath);
Kenny Root02c87302010-07-01 08:10:18 -0700652 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700653 throw e.rethrowFromSystemServer();
Kenny Root02c87302010-07-01 08:10:18 -0700654 }
Kenny Root02c87302010-07-01 08:10:18 -0700655 }
Mike Lockwoodd967f462011-03-24 08:12:30 -0700656
Jeff Sharkey48877892015-03-18 11:27:19 -0700657 /** {@hide} */
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700658 public @NonNull List<DiskInfo> getDisks() {
659 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800660 return Arrays.asList(mStorageManager.getDisks());
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700661 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700662 throw e.rethrowFromSystemServer();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700663 }
664 }
665
666 /** {@hide} */
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700667 public @Nullable DiskInfo findDiskById(String id) {
668 Preconditions.checkNotNull(id);
669 // TODO; go directly to service to make this faster
670 for (DiskInfo disk : getDisks()) {
671 if (Objects.equals(disk.id, id)) {
672 return disk;
673 }
674 }
675 return null;
676 }
677
678 /** {@hide} */
679 public @Nullable VolumeInfo findVolumeById(String id) {
680 Preconditions.checkNotNull(id);
681 // TODO; go directly to service to make this faster
682 for (VolumeInfo vol : getVolumes()) {
683 if (Objects.equals(vol.id, id)) {
684 return vol;
685 }
686 }
687 return null;
688 }
689
690 /** {@hide} */
691 public @Nullable VolumeInfo findVolumeByUuid(String fsUuid) {
692 Preconditions.checkNotNull(fsUuid);
693 // TODO; go directly to service to make this faster
694 for (VolumeInfo vol : getVolumes()) {
695 if (Objects.equals(vol.fsUuid, fsUuid)) {
696 return vol;
697 }
698 }
699 return null;
700 }
701
702 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700703 public @Nullable VolumeRecord findRecordByUuid(String fsUuid) {
704 Preconditions.checkNotNull(fsUuid);
705 // TODO; go directly to service to make this faster
706 for (VolumeRecord rec : getVolumeRecords()) {
707 if (Objects.equals(rec.fsUuid, fsUuid)) {
708 return rec;
709 }
710 }
711 return null;
712 }
713
714 /** {@hide} */
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700715 public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700716 if (emulatedVol != null) {
717 return findVolumeById(emulatedVol.getId().replace("emulated", "private"));
718 } else {
719 return null;
720 }
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700721 }
722
723 /** {@hide} */
724 public @Nullable VolumeInfo findEmulatedForPrivate(VolumeInfo privateVol) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700725 if (privateVol != null) {
726 return findVolumeById(privateVol.getId().replace("private", "emulated"));
727 } else {
728 return null;
729 }
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700730 }
731
732 /** {@hide} */
Jeff Sharkey50a05452015-04-29 11:24:52 -0700733 public @Nullable VolumeInfo findVolumeByQualifiedUuid(String volumeUuid) {
734 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
735 return findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL);
736 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
737 return getPrimaryPhysicalVolume();
738 } else {
739 return findVolumeByUuid(volumeUuid);
740 }
741 }
742
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600743 /**
744 * Return a UUID identifying the storage volume that hosts the given
745 * filesystem path.
746 * <p>
747 * If this path is hosted by the default internal storage of the device at
748 * {@link Environment#getDataDirectory()}, the returned value will be
749 * {@link #UUID_DEFAULT}.
750 *
Jeff Sharkey4233f032017-07-15 12:58:38 -0600751 * @throws IOException when the storage device hosting the given path isn't
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600752 * present, or when it doesn't have a valid UUID.
753 */
754 public @NonNull UUID getUuidForPath(@NonNull File path) throws IOException {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700755 Preconditions.checkNotNull(path);
Jeff Sharkey00347882017-04-17 16:44:12 -0600756 final String pathString = path.getCanonicalPath();
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700757 if (FileUtils.contains(Environment.getDataDirectory().getAbsolutePath(), pathString)) {
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600758 return UUID_DEFAULT;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700759 }
760 try {
761 for (VolumeInfo vol : mStorageManager.getVolumes(0)) {
762 if (vol.path != null && FileUtils.contains(vol.path, pathString)) {
763 // TODO: verify that emulated adopted devices have UUID of
764 // underlying volume
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600765 return convert(vol.fsUuid);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700766 }
767 }
768 } catch (RemoteException e) {
769 throw e.rethrowFromSystemServer();
770 }
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600771 throw new FileNotFoundException("Failed to find a storage device for " + path);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700772 }
773
774 /** {@hide} */
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600775 public @NonNull File findPathForUuid(String volumeUuid) throws FileNotFoundException {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700776 final VolumeInfo vol = findVolumeByQualifiedUuid(volumeUuid);
777 if (vol != null) {
778 return vol.getPath();
779 }
Jeff Sharkey789a8fc2017-04-16 13:18:35 -0600780 throw new FileNotFoundException("Failed to find a storage device for " + volumeUuid);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700781 }
782
Jeff Sharkey4233f032017-07-15 12:58:38 -0600783 /**
784 * Test if the given file descriptor supports allocation of disk space using
785 * {@link #allocateBytes(FileDescriptor, long)}.
786 */
787 public boolean isAllocationSupported(@NonNull FileDescriptor fd) {
788 try {
789 getUuidForPath(ParcelFileDescriptor.getFile(fd));
790 return true;
791 } catch (IOException e) {
792 return false;
793 }
794 }
795
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700796 /** {@hide} */
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700797 public @NonNull List<VolumeInfo> getVolumes() {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700798 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800799 return Arrays.asList(mStorageManager.getVolumes(0));
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700800 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700801 throw e.rethrowFromSystemServer();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700802 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700803 }
804
805 /** {@hide} */
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700806 public @NonNull List<VolumeInfo> getWritablePrivateVolumes() {
807 try {
808 final ArrayList<VolumeInfo> res = new ArrayList<>();
Sudheer Shanka2250d562016-11-07 15:41:02 -0800809 for (VolumeInfo vol : mStorageManager.getVolumes(0)) {
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700810 if (vol.getType() == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) {
811 res.add(vol);
812 }
813 }
814 return res;
815 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700816 throw e.rethrowFromSystemServer();
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700817 }
818 }
819
820 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700821 public @NonNull List<VolumeRecord> getVolumeRecords() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700822 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800823 return Arrays.asList(mStorageManager.getVolumeRecords(0));
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700824 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700825 throw e.rethrowFromSystemServer();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700826 }
827 }
828
829 /** {@hide} */
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700830 public @Nullable String getBestVolumeDescription(VolumeInfo vol) {
Jeff Sharkey50a05452015-04-29 11:24:52 -0700831 if (vol == null) return null;
832
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700833 // Nickname always takes precedence when defined
834 if (!TextUtils.isEmpty(vol.fsUuid)) {
835 final VolumeRecord rec = findRecordByUuid(vol.fsUuid);
Jeff Sharkeyc8406812015-05-04 12:04:09 -0700836 if (rec != null && !TextUtils.isEmpty(rec.nickname)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700837 return rec.nickname;
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700838 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700839 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700840
841 if (!TextUtils.isEmpty(vol.getDescription())) {
842 return vol.getDescription();
843 }
844
845 if (vol.disk != null) {
846 return vol.disk.getDescription();
847 }
848
849 return null;
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700850 }
851
852 /** {@hide} */
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700853 public @Nullable VolumeInfo getPrimaryPhysicalVolume() {
854 final List<VolumeInfo> vols = getVolumes();
855 for (VolumeInfo vol : vols) {
856 if (vol.isPrimaryPhysical()) {
857 return vol;
858 }
859 }
860 return null;
861 }
862
863 /** {@hide} */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700864 public void mount(String volId) {
865 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800866 mStorageManager.mount(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700867 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700868 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700869 }
870 }
871
872 /** {@hide} */
873 public void unmount(String volId) {
874 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800875 mStorageManager.unmount(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700876 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700877 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700878 }
879 }
880
881 /** {@hide} */
882 public void format(String volId) {
883 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800884 mStorageManager.format(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700885 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700886 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700887 }
888 }
889
890 /** {@hide} */
Jeff Sharkey7e19f532017-11-06 13:54:11 -0700891 @Deprecated
Jeff Sharkey9756d752015-05-14 21:07:42 -0700892 public long benchmark(String volId) {
Jeff Sharkey7e19f532017-11-06 13:54:11 -0700893 final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
894 benchmark(volId, new IVoldTaskListener.Stub() {
895 @Override
896 public void onStatus(int status, PersistableBundle extras) {
897 // Ignored
898 }
899
900 @Override
901 public void onFinished(int status, PersistableBundle extras) {
902 result.complete(extras);
903 }
904 });
Jeff Sharkey9756d752015-05-14 21:07:42 -0700905 try {
Jeff Sharkey7e19f532017-11-06 13:54:11 -0700906 // Convert ms to ns
907 return result.get(3, TimeUnit.MINUTES).getLong("run", Long.MAX_VALUE) * 1000000;
908 } catch (Exception e) {
909 return Long.MAX_VALUE;
910 }
911 }
912
913 /** {@hide} */
914 public void benchmark(String volId, IVoldTaskListener listener) {
915 try {
916 mStorageManager.benchmark(volId, listener);
Jeff Sharkey9756d752015-05-14 21:07:42 -0700917 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700918 throw e.rethrowFromSystemServer();
Jeff Sharkey9756d752015-05-14 21:07:42 -0700919 }
920 }
921
922 /** {@hide} */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700923 public void partitionPublic(String diskId) {
924 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800925 mStorageManager.partitionPublic(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700926 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700927 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700928 }
929 }
930
931 /** {@hide} */
932 public void partitionPrivate(String diskId) {
933 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800934 mStorageManager.partitionPrivate(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700935 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700936 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700937 }
938 }
939
940 /** {@hide} */
941 public void partitionMixed(String diskId, int ratio) {
942 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800943 mStorageManager.partitionMixed(diskId, ratio);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700944 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700945 throw e.rethrowFromSystemServer();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700946 }
947 }
948
949 /** {@hide} */
Jeff Sharkeyb42d6942015-04-28 22:25:26 -0700950 public void wipeAdoptableDisks() {
951 // We only wipe devices in "adoptable" locations, which are in a
952 // long-term stable slot/location on the device, where apps have a
953 // reasonable chance of storing sensitive data. (Apps need to go through
954 // SAF to write to transient volumes.)
955 final List<DiskInfo> disks = getDisks();
956 for (DiskInfo disk : disks) {
957 final String diskId = disk.getId();
958 if (disk.isAdoptable()) {
959 Slog.d(TAG, "Found adoptable " + diskId + "; wiping");
960 try {
961 // TODO: switch to explicit wipe command when we have it,
962 // for now rely on the fact that vfat format does a wipe
Sudheer Shanka2250d562016-11-07 15:41:02 -0800963 mStorageManager.partitionPublic(diskId);
Jeff Sharkeyb42d6942015-04-28 22:25:26 -0700964 } catch (Exception e) {
965 Slog.w(TAG, "Failed to wipe " + diskId + ", but soldiering onward", e);
966 }
967 } else {
968 Slog.d(TAG, "Ignorning non-adoptable disk " + disk.getId());
969 }
970 }
971 }
972
973 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700974 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700975 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800976 mStorageManager.setVolumeNickname(fsUuid, nickname);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700977 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700978 throw e.rethrowFromSystemServer();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700979 }
980 }
981
982 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700983 public void setVolumeInited(String fsUuid, boolean inited) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700984 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800985 mStorageManager.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0,
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700986 VolumeRecord.USER_FLAG_INITED);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700987 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700988 throw e.rethrowFromSystemServer();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700989 }
990 }
991
992 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700993 public void setVolumeSnoozed(String fsUuid, boolean snoozed) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700994 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800995 mStorageManager.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0,
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700996 VolumeRecord.USER_FLAG_SNOOZED);
997 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700998 throw e.rethrowFromSystemServer();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700999 }
1000 }
1001
1002 /** {@hide} */
1003 public void forgetVolume(String fsUuid) {
1004 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001005 mStorageManager.forgetVolume(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001006 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001007 throw e.rethrowFromSystemServer();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001008 }
1009 }
1010
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001011 /**
1012 * This is not the API you're looking for.
1013 *
1014 * @see PackageManager#getPrimaryStorageCurrentVolume()
1015 * @hide
1016 */
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001017 public String getPrimaryStorageUuid() {
1018 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001019 return mStorageManager.getPrimaryStorageUuid();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001020 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001021 throw e.rethrowFromSystemServer();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001022 }
1023 }
1024
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001025 /**
1026 * This is not the API you're looking for.
1027 *
1028 * @see PackageManager#movePrimaryStorage(VolumeInfo)
1029 * @hide
1030 */
1031 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001032 try {
Sudheer Shanka2250d562016-11-07 15:41:02 -08001033 mStorageManager.setPrimaryStorageUuid(volumeUuid, callback);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001034 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001035 throw e.rethrowFromSystemServer();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001036 }
1037 }
1038
Felipe Lemec250e452016-04-11 18:44:33 -07001039 /**
1040 * Return the {@link StorageVolume} that contains the given file, or {@code null} if none.
1041 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001042 public @Nullable StorageVolume getStorageVolume(File file) {
1043 return getStorageVolume(getVolumeList(), file);
1044 }
1045
1046 /** {@hide} */
1047 public static @Nullable StorageVolume getStorageVolume(File file, int userId) {
Jeff Sharkey46349872015-07-28 10:49:47 -07001048 return getStorageVolume(getVolumeList(userId, 0), file);
Jeff Sharkey48877892015-03-18 11:27:19 -07001049 }
1050
1051 /** {@hide} */
1052 private static @Nullable StorageVolume getStorageVolume(StorageVolume[] volumes, File file) {
Felipe Lemec250e452016-04-11 18:44:33 -07001053 if (file == null) {
1054 return null;
1055 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001056 try {
Jeff Sharkey983294592015-07-13 10:25:31 -07001057 file = file.getCanonicalFile();
Jeff Sharkey48877892015-03-18 11:27:19 -07001058 } catch (IOException ignored) {
Felipe Lemec250e452016-04-11 18:44:33 -07001059 Slog.d(TAG, "Could not get canonical path for " + file);
Jeff Sharkey983294592015-07-13 10:25:31 -07001060 return null;
Jeff Sharkey48877892015-03-18 11:27:19 -07001061 }
1062 for (StorageVolume volume : volumes) {
Jeff Sharkey983294592015-07-13 10:25:31 -07001063 File volumeFile = volume.getPathFile();
1064 try {
1065 volumeFile = volumeFile.getCanonicalFile();
1066 } catch (IOException ignored) {
1067 continue;
Jeff Sharkey48877892015-03-18 11:27:19 -07001068 }
Jeff Sharkey983294592015-07-13 10:25:31 -07001069 if (FileUtils.contains(volumeFile, file)) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001070 return volume;
1071 }
1072 }
1073 return null;
1074 }
1075
Mike Lockwoodd967f462011-03-24 08:12:30 -07001076 /**
1077 * Gets the state of a volume via its mountpoint.
1078 * @hide
1079 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001080 @Deprecated
1081 public @NonNull String getVolumeState(String mountPoint) {
1082 final StorageVolume vol = getStorageVolume(new File(mountPoint));
1083 if (vol != null) {
1084 return vol.getState();
1085 } else {
1086 return Environment.MEDIA_UNKNOWN;
Mike Lockwoodd967f462011-03-24 08:12:30 -07001087 }
1088 }
1089
Felipe Leme04a5d402016-02-08 16:44:06 -08001090 /**
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001091 * Return the list of shared/external storage volumes available to the
1092 * current user. This includes both the primary shared storage device and
1093 * any attached external volumes including SD cards and USB drives.
Felipe Leme04a5d402016-02-08 16:44:06 -08001094 *
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001095 * @see Environment#getExternalStorageDirectory()
1096 * @see StorageVolume#createAccessIntent(String)
Felipe Leme04a5d402016-02-08 16:44:06 -08001097 */
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06001098 public @NonNull List<StorageVolume> getStorageVolumes() {
1099 final ArrayList<StorageVolume> res = new ArrayList<>();
1100 Collections.addAll(res,
1101 getVolumeList(UserHandle.myUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE));
1102 return res;
1103 }
1104
1105 /**
1106 * Return the primary shared/external storage volume available to the
1107 * current user. This volume is the same storage device returned by
1108 * {@link Environment#getExternalStorageDirectory()} and
1109 * {@link Context#getExternalFilesDir(String)}.
1110 */
1111 public @NonNull StorageVolume getPrimaryStorageVolume() {
1112 return getVolumeList(UserHandle.myUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE)[0];
1113 }
1114
Felipe Leme18202e00b2016-05-12 12:56:28 -07001115 /** {@hide} */
Felipe Leme281389a2016-10-10 17:12:20 -07001116 public static Pair<String, Long> getPrimaryStoragePathAndSize() {
Jeff Sharkey24403ff2017-04-04 15:09:58 -06001117 return Pair.create(null,
1118 FileUtils.roundStorageSize(Environment.getDataDirectory().getTotalSpace()));
Felipe Leme18202e00b2016-05-12 12:56:28 -07001119 }
1120
Felipe Leme281389a2016-10-10 17:12:20 -07001121 /** {@hide} */
1122 public long getPrimaryStorageSize() {
Jeff Sharkey24403ff2017-04-04 15:09:58 -06001123 return FileUtils.roundStorageSize(Environment.getDataDirectory().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 Sharkeybe722152013-02-15 16:56:38 -08001200 private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500 * MB_IN_BYTES;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001201
1202 private static final int DEFAULT_CACHE_PERCENTAGE = 10;
1203 private static final long DEFAULT_CACHE_MAX_BYTES = 5 * GB_IN_BYTES;
1204
Jeff Sharkeybe722152013-02-15 16:56:38 -08001205 private static final long DEFAULT_FULL_THRESHOLD_BYTES = MB_IN_BYTES;
1206
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 Sharkey50a05452015-04-29 11:24:52 -07001477 public static File maybeTranslateEmulatedPathToInternal(File path) {
Jeff Sharkey2063e4f2017-06-06 16:03:24 -06001478 // Disabled now that FUSE has been replaced by sdcardfs
Jeff Sharkey50a05452015-04-29 11:24:52 -07001479 return path;
1480 }
1481
Daichi Hirono9e8d9e22015-11-13 14:37:00 +09001482 /** {@hide} */
Daichi Hirono9fb00182016-11-08 14:12:17 +09001483 @VisibleForTesting
1484 public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
Daichi Hirono812c95d2017-02-08 16:20:20 +09001485 int mode, ProxyFileDescriptorCallback callback, Handler handler, ThreadFactory factory)
Daichi Hirono9fb00182016-11-08 14:12:17 +09001486 throws IOException {
Daichi Hirono2443a092017-04-28 14:53:19 +09001487 Preconditions.checkNotNull(callback);
Daichi Hironod61817e2017-02-13 10:37:11 +09001488 MetricsLogger.count(mContext, "storage_open_proxy_file_descriptor", 1);
Daichi Hirono9fb00182016-11-08 14:12:17 +09001489 // Retry is needed because the mount point mFuseAppLoop is using may be unmounted before
1490 // invoking StorageManagerService#openProxyFileDescriptor. In this case, we need to re-mount
1491 // the bridge by calling mountProxyFileDescriptorBridge.
Daichi Hirono812c95d2017-02-08 16:20:20 +09001492 while (true) {
Daichi Hirono9fb00182016-11-08 14:12:17 +09001493 try {
1494 synchronized (mFuseAppLoopLock) {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001495 boolean newlyCreated = false;
Daichi Hirono9fb00182016-11-08 14:12:17 +09001496 if (mFuseAppLoop == null) {
1497 final AppFuseMount mount = mStorageManager.mountProxyFileDescriptorBridge();
1498 if (mount == null) {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001499 throw new IOException("Failed to mount proxy bridge");
Daichi Hirono9fb00182016-11-08 14:12:17 +09001500 }
Daichi Hirono812c95d2017-02-08 16:20:20 +09001501 mFuseAppLoop = new FuseAppLoop(mount.mountPointId, mount.fd, factory);
1502 newlyCreated = true;
Daichi Hirono9fb00182016-11-08 14:12:17 +09001503 }
Daichi Hirono812c95d2017-02-08 16:20:20 +09001504 if (handler == null) {
1505 handler = new Handler(Looper.getMainLooper());
1506 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09001507 try {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001508 final int fileId = mFuseAppLoop.registerCallback(callback, handler);
1509 final ParcelFileDescriptor pfd = mStorageManager.openProxyFileDescriptor(
1510 mFuseAppLoop.getMountPointId(), fileId, mode);
1511 if (pfd == null) {
1512 mFuseAppLoop.unregisterCallback(fileId);
1513 throw new FuseUnavailableMountException(
1514 mFuseAppLoop.getMountPointId());
Daichi Hirono9fb00182016-11-08 14:12:17 +09001515 }
Daichi Hirono812c95d2017-02-08 16:20:20 +09001516 return pfd;
1517 } catch (FuseUnavailableMountException exception) {
1518 // The bridge is being unmounted. Tried to recreate it unless the bridge was
1519 // just created.
1520 if (newlyCreated) {
1521 throw new IOException(exception);
1522 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09001523 mFuseAppLoop = null;
1524 continue;
1525 }
1526 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09001527 } catch (RemoteException e) {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001528 // Cannot recover from remote exception.
1529 throw new IOException(e);
Daichi Hirono9fb00182016-11-08 14:12:17 +09001530 }
1531 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09001532 }
1533
Daichi Hirono2443a092017-04-28 14:53:19 +09001534 /** {@hide} */
Daichi Hirono9fb00182016-11-08 14:12:17 +09001535 public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
1536 int mode, ProxyFileDescriptorCallback callback)
1537 throws IOException {
Daichi Hirono812c95d2017-02-08 16:20:20 +09001538 return openProxyFileDescriptor(mode, callback, null, null);
Daichi Hirono9fb00182016-11-08 14:12:17 +09001539 }
1540
Daichi Hirono812c95d2017-02-08 16:20:20 +09001541 /**
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001542 * Opens a seekable {@link ParcelFileDescriptor} that proxies all low-level
1543 * I/O requests back to the given {@link ProxyFileDescriptorCallback}.
1544 * <p>
1545 * This can be useful when you want to provide quick access to a large file
1546 * that isn't backed by a real file on disk, such as a file on a network
1547 * share, cloud storage service, etc. As an example, you could respond to a
1548 * {@link ContentResolver#openFileDescriptor(android.net.Uri, String)}
1549 * request by returning a {@link ParcelFileDescriptor} created with this
1550 * method, and then stream the content on-demand as requested.
1551 * <p>
1552 * Another useful example might be where you have an encrypted file that
1553 * you're willing to decrypt on-demand, but where you want to avoid
1554 * persisting the cleartext version.
Daichi Hirono812c95d2017-02-08 16:20:20 +09001555 *
1556 * @param mode The desired access mode, must be one of
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001557 * {@link ParcelFileDescriptor#MODE_READ_ONLY},
1558 * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or
1559 * {@link ParcelFileDescriptor#MODE_READ_WRITE}
1560 * @param callback Callback to process file operation requests issued on
1561 * returned file descriptor.
Daichi Hirono812c95d2017-02-08 16:20:20 +09001562 * @param handler Handler that invokes callback methods.
1563 * @return Seekable ParcelFileDescriptor.
1564 * @throws IOException
1565 */
1566 public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
1567 int mode, ProxyFileDescriptorCallback callback, Handler handler)
1568 throws IOException {
Daichi Hirono2443a092017-04-28 14:53:19 +09001569 Preconditions.checkNotNull(handler);
Daichi Hirono812c95d2017-02-08 16:20:20 +09001570 return openProxyFileDescriptor(mode, callback, handler, null);
1571 }
1572
Daichi Hirono9fb00182016-11-08 14:12:17 +09001573 /** {@hide} */
1574 @VisibleForTesting
1575 public int getProxyFileDescriptorMountPointId() {
1576 synchronized (mFuseAppLoopLock) {
1577 return mFuseAppLoop != null ? mFuseAppLoop.getMountPointId() : -1;
1578 }
1579 }
1580
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001581 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001582 * Return quota size in bytes for all cached data belonging to the calling
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001583 * app on the given storage volume.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001584 * <p>
1585 * If your app goes above this quota, your cached files will be some of the
1586 * first to be deleted when additional disk space is needed. Conversely, if
1587 * your app stays under this quota, your cached files will be some of the
1588 * last to be deleted when additional disk space is needed.
1589 * <p>
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001590 * This quota will change over time depending on how frequently the user
Jeff Sharkey60a82cd2017-04-18 18:19:16 -06001591 * interacts with your app, and depending on how much system-wide disk space
1592 * is used.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001593 * <p class="note">
1594 * Note: if your app uses the {@code android:sharedUserId} manifest feature,
1595 * then cached data for all packages in your shared UID is tracked together
1596 * as a single unit.
1597 * </p>
1598 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001599 * @param storageUuid the UUID of the storage volume that you're interested
1600 * in. The UUID for a specific path can be obtained using
1601 * {@link #getUuidForPath(File)}.
1602 * @throws IOException when the storage device isn't present, or when it
1603 * doesn't support cache quotas.
1604 * @see #getCacheSizeBytes(UUID)
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001605 */
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001606 @WorkerThread
1607 public @BytesLong long getCacheQuotaBytes(@NonNull UUID storageUuid) throws IOException {
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001608 try {
1609 final ApplicationInfo app = mContext.getApplicationInfo();
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001610 return mStorageManager.getCacheQuotaBytes(convert(storageUuid), app.uid);
1611 } catch (ParcelableException e) {
1612 e.maybeRethrow(IOException.class);
1613 throw new RuntimeException(e);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001614 } catch (RemoteException e) {
1615 throw e.rethrowFromSystemServer();
1616 }
1617 }
1618
1619 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001620 * Return total size in bytes of all cached data belonging to the calling
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001621 * app on the given storage volume.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001622 * <p>
1623 * Cached data tracked by this method always includes
1624 * {@link Context#getCacheDir()} and {@link Context#getCodeCacheDir()}, and
1625 * it also includes {@link Context#getExternalCacheDir()} if the primary
1626 * shared/external storage is hosted on the same storage device as your
1627 * private data.
1628 * <p class="note">
1629 * Note: if your app uses the {@code android:sharedUserId} manifest feature,
1630 * then cached data for all packages in your shared UID is tracked together
1631 * as a single unit.
1632 * </p>
1633 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001634 * @param storageUuid the UUID of the storage volume that you're interested
1635 * in. The UUID for a specific path can be obtained using
1636 * {@link #getUuidForPath(File)}.
1637 * @throws IOException when the storage device isn't present, or when it
1638 * doesn't support cache quotas.
1639 * @see #getCacheQuotaBytes(UUID)
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001640 */
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001641 @WorkerThread
1642 public @BytesLong long getCacheSizeBytes(@NonNull UUID storageUuid) throws IOException {
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001643 try {
1644 final ApplicationInfo app = mContext.getApplicationInfo();
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001645 return mStorageManager.getCacheSizeBytes(convert(storageUuid), app.uid);
1646 } catch (ParcelableException e) {
1647 e.maybeRethrow(IOException.class);
1648 throw new RuntimeException(e);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001649 } catch (RemoteException e) {
1650 throw e.rethrowFromSystemServer();
1651 }
1652 }
1653
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001654 /**
1655 * Flag indicating that a disk space allocation request should operate in an
1656 * aggressive mode. This flag should only be rarely used in situations that
1657 * are critical to system health or security.
1658 * <p>
1659 * When set, the system is more aggressive about the data that it considers
1660 * for possible deletion when allocating disk space.
1661 * <p class="note">
1662 * Note: your app must hold the
1663 * {@link android.Manifest.permission#ALLOCATE_AGGRESSIVE} permission for
1664 * this flag to take effect.
1665 * </p>
1666 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001667 * @see #getAllocatableBytes(UUID, int)
1668 * @see #allocateBytes(UUID, long, int)
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001669 * @see #allocateBytes(FileDescriptor, long, int)
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001670 * @hide
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001671 */
1672 @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE)
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001673 @SystemApi
Jeff Sharkeyddff8072017-05-26 13:10:46 -06001674 public static final int FLAG_ALLOCATE_AGGRESSIVE = 1 << 0;
1675
1676 /**
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001677 * Flag indicating that a disk space allocation request should be allowed to
1678 * clear up to all reserved disk space.
Jeff Sharkeyddff8072017-05-26 13:10:46 -06001679 *
1680 * @hide
1681 */
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001682 public static final int FLAG_ALLOCATE_DEFY_ALL_RESERVED = 1 << 1;
1683
1684 /**
1685 * Flag indicating that a disk space allocation request should be allowed to
1686 * clear up to half of all reserved disk space.
1687 *
1688 * @hide
1689 */
1690 public static final int FLAG_ALLOCATE_DEFY_HALF_RESERVED = 1 << 2;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001691
1692 /** @hide */
1693 @IntDef(flag = true, value = {
1694 FLAG_ALLOCATE_AGGRESSIVE,
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001695 FLAG_ALLOCATE_DEFY_ALL_RESERVED,
1696 FLAG_ALLOCATE_DEFY_HALF_RESERVED,
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001697 })
1698 @Retention(RetentionPolicy.SOURCE)
1699 public @interface AllocateFlags {}
1700
1701 /**
1702 * Return the maximum number of new bytes that your app can allocate for
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001703 * itself on the given storage volume. This value is typically larger than
1704 * {@link File#getUsableSpace()}, since the system may be willing to delete
1705 * cached files to satisfy an allocation request. You can then allocate
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001706 * space for yourself using {@link #allocateBytes(UUID, long)} or
1707 * {@link #allocateBytes(FileDescriptor, long)}.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001708 * <p>
1709 * This method is best used as a pre-flight check, such as deciding if there
1710 * is enough space to store an entire music album before you allocate space
1711 * for each audio file in the album. Attempts to allocate disk space beyond
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001712 * the returned value will fail.
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001713 * <p>
1714 * If the returned value is not large enough for the data you'd like to
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001715 * persist, you can launch {@link #ACTION_MANAGE_STORAGE} with the
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001716 * {@link #EXTRA_UUID} and {@link #EXTRA_REQUESTED_BYTES} options to help
1717 * involve the user in freeing up disk space.
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001718 * <p>
1719 * If you're progressively allocating an unbounded amount of storage space
1720 * (such as when recording a video) you should avoid calling this method
1721 * more than once every 30 seconds.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001722 * <p class="note">
1723 * Note: if your app uses the {@code android:sharedUserId} manifest feature,
1724 * then allocatable space for all packages in your shared UID is tracked
1725 * together as a single unit.
1726 * </p>
1727 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001728 * @param storageUuid the UUID of the storage volume where you're
1729 * considering allocating disk space, since allocatable space can
1730 * vary widely depending on the underlying storage device. The
1731 * UUID for a specific path can be obtained using
1732 * {@link #getUuidForPath(File)}.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001733 * @return the maximum number of new bytes that the calling app can allocate
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001734 * using {@link #allocateBytes(UUID, long)} or
1735 * {@link #allocateBytes(FileDescriptor, long)}.
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001736 * @throws IOException when the storage device isn't present, or when it
1737 * doesn't support allocating space.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001738 */
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001739 @WorkerThread
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001740 public @BytesLong long getAllocatableBytes(@NonNull UUID storageUuid)
1741 throws IOException {
1742 return getAllocatableBytes(storageUuid, 0);
1743 }
1744
1745 /** @hide */
1746 @SystemApi
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001747 @WorkerThread
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -06001748 @SuppressLint("Doclava125")
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001749 public long getAllocatableBytes(@NonNull UUID storageUuid,
1750 @RequiresPermission @AllocateFlags int flags) throws IOException {
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001751 try {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001752 return mStorageManager.getAllocatableBytes(convert(storageUuid), flags,
1753 mContext.getOpPackageName());
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001754 } catch (ParcelableException e) {
1755 e.maybeRethrow(IOException.class);
1756 throw new RuntimeException(e);
1757 } catch (RemoteException e) {
1758 throw e.rethrowFromSystemServer();
1759 }
1760 }
1761
1762 /**
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001763 * Allocate the requested number of bytes for your application to use on the
1764 * given storage volume. This will cause the system to delete any cached
1765 * files necessary to satisfy your request.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001766 * <p>
1767 * Attempts to allocate disk space beyond the value returned by
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001768 * {@link #getAllocatableBytes(UUID)} will fail.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001769 * <p>
1770 * Since multiple apps can be running simultaneously, this method may be
1771 * subject to race conditions. If possible, consider using
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001772 * {@link #allocateBytes(FileDescriptor, long)} which will guarantee
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001773 * that bytes are allocated to an opened file.
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001774 * <p>
1775 * If you're progressively allocating an unbounded amount of storage space
1776 * (such as when recording a video) you should avoid calling this method
1777 * more than once every 60 seconds.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001778 *
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001779 * @param storageUuid the UUID of the storage volume where you'd like to
1780 * allocate disk space. The UUID for a specific path can be
1781 * obtained using {@link #getUuidForPath(File)}.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001782 * @param bytes the number of bytes to allocate.
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001783 * @throws IOException when the storage device isn't present, or when it
1784 * doesn't support allocating space, or if the device had
1785 * trouble allocating the requested space.
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001786 * @see #getAllocatableBytes(UUID)
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001787 */
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001788 @WorkerThread
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001789 public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes)
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001790 throws IOException {
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001791 allocateBytes(storageUuid, bytes, 0);
1792 }
1793
1794 /** @hide */
1795 @SystemApi
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001796 @WorkerThread
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -06001797 @SuppressLint("Doclava125")
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001798 public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes,
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001799 @RequiresPermission @AllocateFlags int flags) throws IOException {
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001800 try {
Jeff Sharkey35e46d22017-06-09 10:01:20 -06001801 mStorageManager.allocateBytes(convert(storageUuid), bytes, flags,
1802 mContext.getOpPackageName());
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001803 } catch (ParcelableException e) {
1804 e.maybeRethrow(IOException.class);
1805 } catch (RemoteException e) {
1806 throw e.rethrowFromSystemServer();
1807 }
1808 }
1809
1810 /**
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001811 * Allocate the requested number of bytes for your application to use in the
1812 * given open file. This will cause the system to delete any cached files
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001813 * necessary to satisfy your request.
1814 * <p>
1815 * Attempts to allocate disk space beyond the value returned by
Jeff Sharkey67f9d502017-08-05 13:49:13 -06001816 * {@link #getAllocatableBytes(UUID)} will fail.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001817 * <p>
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001818 * This method guarantees that bytes have been allocated to the opened file,
1819 * otherwise it will throw if fast allocation is not possible. Fast
1820 * allocation is typically only supported in private app data directories,
1821 * and on shared/external storage devices which are emulated.
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001822 * <p>
1823 * If you're progressively allocating an unbounded amount of storage space
1824 * (such as when recording a video) you should avoid calling this method
1825 * more than once every 60 seconds.
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001826 *
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001827 * @param fd the open file that you'd like to allocate disk space for.
1828 * @param bytes the number of bytes to allocate. This is the desired final
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001829 * size of the open file. If the open file is smaller than this
1830 * requested size, it will be extended without modifying any
1831 * existing contents. If the open file is larger than this
1832 * requested size, it will be truncated.
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001833 * @throws IOException when the storage device isn't present, or when it
1834 * doesn't support allocating space, or if the device had
1835 * trouble allocating the requested space.
1836 * @see #getAllocatableBytes(UUID, int)
Jeff Sharkey4233f032017-07-15 12:58:38 -06001837 * @see #isAllocationSupported(FileDescriptor)
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001838 * @see Environment#isExternalStorageEmulated(File)
1839 */
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001840 @WorkerThread
Jeff Sharkeya4d34d92017-04-27 11:21:41 -06001841 public void allocateBytes(FileDescriptor fd, @BytesLong long bytes) throws IOException {
1842 allocateBytes(fd, bytes, 0);
1843 }
1844
1845 /** @hide */
1846 @SystemApi
Jeff Sharkeyb31afd22017-06-12 14:17:10 -06001847 @WorkerThread
Jeff Sharkeybfc4fcd2017-06-05 17:38:17 -06001848 @SuppressLint("Doclava125")
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001849 public void allocateBytes(FileDescriptor fd, @BytesLong long bytes,
1850 @RequiresPermission @AllocateFlags int flags) throws IOException {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001851 final File file = ParcelFileDescriptor.getFile(fd);
Jeff Sharkey4233f032017-07-15 12:58:38 -06001852 final UUID uuid = getUuidForPath(file);
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001853 for (int i = 0; i < 3; i++) {
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001854 try {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001855 final long haveBytes = Os.fstat(fd).st_blocks * 512;
1856 final long needBytes = bytes - haveBytes;
1857
1858 if (needBytes > 0) {
Jeff Sharkey4233f032017-07-15 12:58:38 -06001859 allocateBytes(uuid, needBytes, flags);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07001860 }
1861
Jeff Sharkey4233f032017-07-15 12:58:38 -06001862 try {
1863 Os.posix_fallocate(fd, 0, bytes);
1864 return;
1865 } catch (ErrnoException e) {
1866 if (e.errno == OsConstants.ENOSYS || e.errno == OsConstants.ENOTSUP) {
1867 Log.w(TAG, "fallocate() not supported; falling back to ftruncate()");
1868 Os.ftruncate(fd, bytes);
1869 return;
1870 } else {
1871 throw e;
1872 }
1873 }
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07001874 } catch (ErrnoException e) {
1875 if (e.errno == OsConstants.ENOSPC) {
1876 Log.w(TAG, "Odd, not enough space; let's try again?");
1877 continue;
1878 }
1879 throw e.rethrowAsIOException();
1880 }
1881 }
1882 throw new IOException(
1883 "Well this is embarassing; we can't allocate " + bytes + " for " + file);
1884 }
1885
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06001886 private static final String XATTR_CACHE_GROUP = "user.cache_group";
Jeff Sharkey458428e2017-02-22 11:47:15 -07001887 private static final String XATTR_CACHE_TOMBSTONE = "user.cache_tombstone";
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001888
1889 /** {@hide} */
1890 private static void setCacheBehavior(File path, String name, boolean enabled)
1891 throws IOException {
1892 if (!path.isDirectory()) {
1893 throw new IOException("Cache behavior can only be set on directories");
1894 }
1895 if (enabled) {
1896 try {
1897 Os.setxattr(path.getAbsolutePath(), name,
1898 "1".getBytes(StandardCharsets.UTF_8), 0);
1899 } catch (ErrnoException e) {
1900 throw e.rethrowAsIOException();
1901 }
1902 } else {
1903 try {
1904 Os.removexattr(path.getAbsolutePath(), name);
1905 } catch (ErrnoException e) {
1906 if (e.errno != OsConstants.ENODATA) {
1907 throw e.rethrowAsIOException();
1908 }
1909 }
1910 }
1911 }
1912
1913 /** {@hide} */
1914 private static boolean isCacheBehavior(File path, String name) throws IOException {
1915 try {
1916 Os.getxattr(path.getAbsolutePath(), name);
1917 return true;
1918 } catch (ErrnoException e) {
1919 if (e.errno != OsConstants.ENODATA) {
1920 throw e.rethrowAsIOException();
1921 } else {
1922 return false;
1923 }
1924 }
1925 }
1926
1927 /**
1928 * Enable or disable special cache behavior that treats this directory and
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06001929 * its contents as an entire group.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001930 * <p>
1931 * When enabled and this directory is considered for automatic deletion by
1932 * the OS, all contained files will either be deleted together, or not at
1933 * all. This is useful when you have a directory that contains several
1934 * related metadata files that depend on each other, such as movie file and
1935 * a subtitle file.
1936 * <p>
1937 * When enabled, the <em>newest</em> {@link File#lastModified()} value of
1938 * any contained files is considered the modified time of the entire
1939 * directory.
1940 * <p>
1941 * This behavior can only be set on a directory, and it applies recursively
1942 * to all contained files and directories.
1943 */
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06001944 public void setCacheBehaviorGroup(File path, boolean group) throws IOException {
1945 setCacheBehavior(path, XATTR_CACHE_GROUP, group);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001946 }
1947
1948 /**
1949 * Read the current value set by
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06001950 * {@link #setCacheBehaviorGroup(File, boolean)}.
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001951 */
Jeff Sharkeyb5a35b82017-03-22 21:30:19 -06001952 public boolean isCacheBehaviorGroup(File path) throws IOException {
1953 return isCacheBehavior(path, XATTR_CACHE_GROUP);
1954 }
1955
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001956 /**
1957 * Enable or disable special cache behavior that leaves deleted cache files
1958 * intact as tombstones.
1959 * <p>
1960 * When enabled and a file contained in this directory is automatically
1961 * deleted by the OS, the file will be truncated to have a length of 0 bytes
1962 * instead of being fully deleted. This is useful if you need to distinguish
1963 * between a file that was deleted versus one that never existed.
1964 * <p>
1965 * This behavior can only be set on a directory, and it applies recursively
1966 * to all contained files and directories.
1967 * <p class="note">
1968 * Note: this behavior is ignored completely if the user explicitly requests
1969 * that all cached data be cleared.
1970 * </p>
1971 */
1972 public void setCacheBehaviorTombstone(File path, boolean tombstone) throws IOException {
Jeff Sharkey458428e2017-02-22 11:47:15 -07001973 setCacheBehavior(path, XATTR_CACHE_TOMBSTONE, tombstone);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001974 }
1975
1976 /**
1977 * Read the current value set by
1978 * {@link #setCacheBehaviorTombstone(File, boolean)}.
1979 */
1980 public boolean isCacheBehaviorTombstone(File path) throws IOException {
Jeff Sharkey458428e2017-02-22 11:47:15 -07001981 return isCacheBehavior(path, XATTR_CACHE_TOMBSTONE);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07001982 }
1983
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06001984 /** {@hide} */
1985 public static UUID convert(String uuid) {
1986 if (Objects.equals(uuid, UUID_PRIVATE_INTERNAL)) {
1987 return UUID_DEFAULT;
1988 } else if (Objects.equals(uuid, UUID_PRIMARY_PHYSICAL)) {
1989 return UUID_PRIMARY_PHYSICAL_;
1990 } else if (Objects.equals(uuid, UUID_SYSTEM)) {
1991 return UUID_SYSTEM_;
1992 } else {
1993 return UUID.fromString(uuid);
1994 }
1995 }
1996
1997 /** {@hide} */
1998 public static String convert(UUID storageUuid) {
1999 if (UUID_DEFAULT.equals(storageUuid)) {
2000 return UUID_PRIVATE_INTERNAL;
2001 } else if (UUID_PRIMARY_PHYSICAL_.equals(storageUuid)) {
2002 return UUID_PRIMARY_PHYSICAL;
2003 } else if (UUID_SYSTEM_.equals(storageUuid)) {
2004 return UUID_SYSTEM;
2005 } else {
2006 return storageUuid.toString();
2007 }
2008 }
2009
Daichi Hirono9fb00182016-11-08 14:12:17 +09002010 private final Object mFuseAppLoopLock = new Object();
2011
2012 @GuardedBy("mFuseAppLoopLock")
2013 private @Nullable FuseAppLoop mFuseAppLoop = null;
2014
Paul Lawrencee8fdc542014-05-28 07:14:17 -07002015 /// Consts to match the password types in cryptfs.h
2016 /** @hide */
Jeff Sharkey43e12112017-09-12 16:31:45 -06002017 public static final int CRYPT_TYPE_PASSWORD = IVold.PASSWORD_TYPE_PASSWORD;
Paul Lawrencee8fdc542014-05-28 07:14:17 -07002018 /** @hide */
Jeff Sharkey43e12112017-09-12 16:31:45 -06002019 public static final int CRYPT_TYPE_DEFAULT = IVold.PASSWORD_TYPE_DEFAULT;
Paul Lawrencee8fdc542014-05-28 07:14:17 -07002020 /** @hide */
Jeff Sharkey43e12112017-09-12 16:31:45 -06002021 public static final int CRYPT_TYPE_PATTERN = IVold.PASSWORD_TYPE_PATTERN;
Paul Lawrencee8fdc542014-05-28 07:14:17 -07002022 /** @hide */
Jeff Sharkey43e12112017-09-12 16:31:45 -06002023 public static final int CRYPT_TYPE_PIN = IVold.PASSWORD_TYPE_PIN;
Elliott Hughesf839b4f2014-09-26 12:30:47 -07002024
Sudheer Shanka2250d562016-11-07 15:41:02 -08002025 // Constants for the data available via StorageManagerService.getField.
Elliott Hughesf839b4f2014-09-26 12:30:47 -07002026 /** @hide */
2027 public static final String SYSTEM_LOCALE_KEY = "SystemLocale";
2028 /** @hide */
2029 public static final String OWNER_INFO_KEY = "OwnerInfo";
2030 /** @hide */
2031 public static final String PATTERN_VISIBLE_KEY = "PatternVisible";
Paul Lawrenced8fdb332015-05-18 13:26:11 -07002032 /** @hide */
2033 public static final String PASSWORD_VISIBLE_KEY = "PasswordVisible";
San Mehatb1043402010-02-05 08:26:50 -08002034}