blob: 97ee90dc9ea23611299904296e2c4cd3a73a65e4 [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 Sharkeybe722152013-02-15 16:56:38 -080019import static android.net.TrafficStats.MB_IN_BYTES;
20
Jeff Sharkey48877892015-03-18 11:27:19 -070021import android.annotation.NonNull;
22import android.annotation.Nullable;
Svet Ganov6ee871e2015-07-10 14:29:33 -070023import android.app.ActivityThread;
Jeff Sharkeybe722152013-02-15 16:56:38 -080024import android.content.ContentResolver;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070025import android.content.Context;
Jeff Sharkey275e3e42015-04-24 16:10:32 -070026import android.content.pm.IPackageMoveObserver;
27import android.content.pm.PackageManager;
Mike Lockwoodcba928c2011-08-17 15:58:52 -070028import android.os.Environment;
Jeff Sharkey48877892015-03-18 11:27:19 -070029import android.os.FileUtils;
San Mehatb1043402010-02-05 08:26:50 -080030import android.os.Handler;
Kenny Roota02b8b02010-08-05 16:14:17 -070031import android.os.Looper;
San Mehatb1043402010-02-05 08:26:50 -080032import android.os.Message;
Daichi Hirono9e8d9e22015-11-13 14:37:00 +090033import android.os.ParcelFileDescriptor;
Kenny Roota02b8b02010-08-05 16:14:17 -070034import android.os.RemoteException;
San Mehatb1043402010-02-05 08:26:50 -080035import android.os.ServiceManager;
Jeff Sharkeyba512352015-11-12 20:17:45 -080036import android.os.SystemProperties;
Jeff Sharkeybe722152013-02-15 16:56:38 -080037import android.provider.Settings;
Jeff Sharkey59d577a2015-04-11 21:27:21 -070038import android.text.TextUtils;
San Mehatb1043402010-02-05 08:26:50 -080039import android.util.Log;
Jeff Sharkeyb42d6942015-04-28 22:25:26 -070040import android.util.Slog;
Kenny Rootaf9d6672010-10-08 09:21:39 -070041import android.util.SparseArray;
San Mehatb1043402010-02-05 08:26:50 -080042
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070043import com.android.internal.os.SomeArgs;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -070044import com.android.internal.util.Preconditions;
45
46import java.io.File;
47import java.io.IOException;
Kenny Root05105f72010-09-22 17:29:43 -070048import java.lang.ref.WeakReference;
San Mehatb1043402010-02-05 08:26:50 -080049import java.util.ArrayList;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070050import java.util.Arrays;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070051import java.util.Iterator;
Kenny Root05105f72010-09-22 17:29:43 -070052import java.util.List;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070053import java.util.Objects;
Kenny Rootaf9d6672010-10-08 09:21:39 -070054import java.util.concurrent.atomic.AtomicInteger;
San Mehatb1043402010-02-05 08:26:50 -080055
56/**
Kenny Root05105f72010-09-22 17:29:43 -070057 * StorageManager is the interface to the systems storage service. The storage
58 * manager handles storage-related items such as Opaque Binary Blobs (OBBs).
59 * <p>
60 * OBBs contain a filesystem that maybe be encrypted on disk and mounted
61 * on-demand from an application. OBBs are a good way of providing large amounts
62 * of binary assets without packaging them into APKs as they may be multiple
63 * gigabytes in size. However, due to their size, they're most likely stored in
64 * a shared storage pool accessible from all programs. The system does not
65 * guarantee the security of the OBB file itself: if any program modifies the
66 * OBB, there is no guarantee that a read from that OBB will produce the
67 * expected output.
68 * <p>
San Mehatb1043402010-02-05 08:26:50 -080069 * Get an instance of this class by calling
Kenny Root05105f72010-09-22 17:29:43 -070070 * {@link android.content.Context#getSystemService(java.lang.String)} with an
71 * argument of {@link android.content.Context#STORAGE_SERVICE}.
San Mehatb1043402010-02-05 08:26:50 -080072 */
Jeff Sharkeybe722152013-02-15 16:56:38 -080073public class StorageManager {
San Mehatb1043402010-02-05 08:26:50 -080074 private static final String TAG = "StorageManager";
75
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070076 /** {@hide} */
77 public static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical";
Jeff Sharkey74acbbb2015-04-21 12:14:03 -070078 /** {@hide} */
Jeff Sharkey0d838a02015-05-13 13:54:30 -070079 public static final String PROP_HAS_ADOPTABLE = "vold.has_adoptable";
80 /** {@hide} */
Jeff Sharkey74acbbb2015-04-21 12:14:03 -070081 public static final String PROP_FORCE_ADOPTABLE = "persist.fw.force_adoptable";
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -080082 /** {@hide} */
Jeff Sharkeyba512352015-11-12 20:17:45 -080083 public static final String PROP_EMULATE_FBE = "persist.sys.emulate_fbe";
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070084
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070085 /** {@hide} */
Jeff Sharkey620b32b2015-04-23 19:36:02 -070086 public static final String UUID_PRIVATE_INTERNAL = null;
87 /** {@hide} */
88 public static final String UUID_PRIMARY_PHYSICAL = "primary_physical";
89
Jeff Sharkey4c099d02015-05-15 13:45:00 -070090 /** {@hide} */
91 public static final int DEBUG_FORCE_ADOPTABLE = 1 << 0;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -080092 /** {@hide} */
93 public static final int DEBUG_EMULATE_FBE = 1 << 1;
Jeff Sharkey4c099d02015-05-15 13:45:00 -070094
Jeff Sharkey47f71082016-02-01 17:03:54 -070095 // NOTE: keep in sync with installd
Jeff Sharkey46349872015-07-28 10:49:47 -070096 /** {@hide} */
Jeff Sharkey47f71082016-02-01 17:03:54 -070097 public static final int FLAG_STORAGE_DE = 1 << 0;
98 /** {@hide} */
99 public static final int FLAG_STORAGE_CE = 1 << 1;
100
101 /** {@hide} */
102 public static final int FLAG_FOR_WRITE = 1 << 8;
Jeff Sharkey46349872015-07-28 10:49:47 -0700103
Jeff Sharkey48877892015-03-18 11:27:19 -0700104 private final Context mContext;
Jeff Sharkeybe722152013-02-15 16:56:38 -0800105 private final ContentResolver mResolver;
106
Jeff Sharkeybe722152013-02-15 16:56:38 -0800107 private final IMountService mMountService;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700108 private final Looper mLooper;
109 private final AtomicInteger mNextNonce = new AtomicInteger(0);
San Mehatb1043402010-02-05 08:26:50 -0800110
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700111 private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>();
San Mehatb1043402010-02-05 08:26:50 -0800112
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700113 private static class StorageEventListenerDelegate extends IMountServiceListener.Stub implements
114 Handler.Callback {
115 private static final int MSG_STORAGE_STATE_CHANGED = 1;
116 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700117 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
118 private static final int MSG_VOLUME_FORGOTTEN = 4;
119 private static final int MSG_DISK_SCANNED = 5;
Makoto Onuki9dc575d2015-06-12 16:10:25 -0700120 private static final int MSG_DISK_DESTROYED = 6;
San Mehatb1043402010-02-05 08:26:50 -0800121
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700122 final StorageEventListener mCallback;
123 final Handler mHandler;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700124
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700125 public StorageEventListenerDelegate(StorageEventListener callback, Looper looper) {
126 mCallback = callback;
127 mHandler = new Handler(looper, this);
San Mehatb1043402010-02-05 08:26:50 -0800128 }
129
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700130 @Override
131 public boolean handleMessage(Message msg) {
132 final SomeArgs args = (SomeArgs) msg.obj;
133 switch (msg.what) {
134 case MSG_STORAGE_STATE_CHANGED:
135 mCallback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
136 (String) args.arg3);
137 args.recycle();
138 return true;
139 case MSG_VOLUME_STATE_CHANGED:
140 mCallback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
141 args.recycle();
142 return true;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700143 case MSG_VOLUME_RECORD_CHANGED:
144 mCallback.onVolumeRecordChanged((VolumeRecord) args.arg1);
145 args.recycle();
146 return true;
147 case MSG_VOLUME_FORGOTTEN:
148 mCallback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700149 args.recycle();
150 return true;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700151 case MSG_DISK_SCANNED:
152 mCallback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700153 args.recycle();
154 return true;
Makoto Onuki9dc575d2015-06-12 16:10:25 -0700155 case MSG_DISK_DESTROYED:
156 mCallback.onDiskDestroyed((DiskInfo) args.arg1);
157 args.recycle();
158 return true;
San Mehatb1043402010-02-05 08:26:50 -0800159 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700160 args.recycle();
161 return false;
162 }
163
164 @Override
165 public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException {
166 // Ignored
167 }
168
169 @Override
170 public void onStorageStateChanged(String path, String oldState, String newState) {
171 final SomeArgs args = SomeArgs.obtain();
172 args.arg1 = path;
173 args.arg2 = oldState;
174 args.arg3 = newState;
175 mHandler.obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
176 }
177
178 @Override
179 public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
180 final SomeArgs args = SomeArgs.obtain();
181 args.arg1 = vol;
182 args.argi2 = oldState;
183 args.argi3 = newState;
184 mHandler.obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
San Mehatb1043402010-02-05 08:26:50 -0800185 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700186
187 @Override
Jeff Sharkey50a05452015-04-29 11:24:52 -0700188 public void onVolumeRecordChanged(VolumeRecord rec) {
189 final SomeArgs args = SomeArgs.obtain();
190 args.arg1 = rec;
191 mHandler.obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
192 }
193
194 @Override
195 public void onVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700196 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700197 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700198 mHandler.obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700199 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700200
201 @Override
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700202 public void onDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700203 final SomeArgs args = SomeArgs.obtain();
204 args.arg1 = disk;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700205 args.argi2 = volumeCount;
206 mHandler.obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700207 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -0700208
209 @Override
210 public void onDiskDestroyed(DiskInfo disk) throws RemoteException {
211 final SomeArgs args = SomeArgs.obtain();
212 args.arg1 = disk;
213 mHandler.obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
214 }
San Mehatb1043402010-02-05 08:26:50 -0800215 }
216
217 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700218 * Binder listener for OBB action results.
219 */
Kenny Root05105f72010-09-22 17:29:43 -0700220 private final ObbActionListener mObbActionListener = new ObbActionListener();
221
222 private class ObbActionListener extends IObbActionListener.Stub {
Gilles Debunne37051cd2011-05-25 16:27:13 -0700223 @SuppressWarnings("hiding")
Kenny Rootaf9d6672010-10-08 09:21:39 -0700224 private SparseArray<ObbListenerDelegate> mListeners = new SparseArray<ObbListenerDelegate>();
Kenny Root05105f72010-09-22 17:29:43 -0700225
Kenny Roota02b8b02010-08-05 16:14:17 -0700226 @Override
Gilles Debunne37051cd2011-05-25 16:27:13 -0700227 public void onObbResult(String filename, int nonce, int status) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700228 final ObbListenerDelegate delegate;
Kenny Root05105f72010-09-22 17:29:43 -0700229 synchronized (mListeners) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700230 delegate = mListeners.get(nonce);
231 if (delegate != null) {
232 mListeners.remove(nonce);
Kenny Root05105f72010-09-22 17:29:43 -0700233 }
234 }
Kenny Rootaf9d6672010-10-08 09:21:39 -0700235
236 if (delegate != null) {
237 delegate.sendObbStateChanged(filename, status);
238 }
Kenny Root05105f72010-09-22 17:29:43 -0700239 }
240
Kenny Rootaf9d6672010-10-08 09:21:39 -0700241 public int addListener(OnObbStateChangeListener listener) {
242 final ObbListenerDelegate delegate = new ObbListenerDelegate(listener);
Kenny Root05105f72010-09-22 17:29:43 -0700243
244 synchronized (mListeners) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700245 mListeners.put(delegate.nonce, delegate);
Kenny Root05105f72010-09-22 17:29:43 -0700246 }
Kenny Rootaf9d6672010-10-08 09:21:39 -0700247
248 return delegate.nonce;
Kenny Root05105f72010-09-22 17:29:43 -0700249 }
250 }
251
Kenny Rootaf9d6672010-10-08 09:21:39 -0700252 private int getNextNonce() {
253 return mNextNonce.getAndIncrement();
254 }
255
Kenny Root05105f72010-09-22 17:29:43 -0700256 /**
257 * Private class containing sender and receiver code for StorageEvents.
258 */
259 private class ObbListenerDelegate {
260 private final WeakReference<OnObbStateChangeListener> mObbEventListenerRef;
261 private final Handler mHandler;
262
Kenny Rootaf9d6672010-10-08 09:21:39 -0700263 private final int nonce;
264
Kenny Root05105f72010-09-22 17:29:43 -0700265 ObbListenerDelegate(OnObbStateChangeListener listener) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700266 nonce = getNextNonce();
Kenny Root05105f72010-09-22 17:29:43 -0700267 mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700268 mHandler = new Handler(mLooper) {
Kenny Root05105f72010-09-22 17:29:43 -0700269 @Override
270 public void handleMessage(Message msg) {
Gilles Debunne37051cd2011-05-25 16:27:13 -0700271 final OnObbStateChangeListener changeListener = getListener();
272 if (changeListener == null) {
Kenny Root05105f72010-09-22 17:29:43 -0700273 return;
274 }
275
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700276 changeListener.onObbStateChange((String) msg.obj, msg.arg1);
Kenny Root05105f72010-09-22 17:29:43 -0700277 }
278 };
279 }
280
281 OnObbStateChangeListener getListener() {
282 if (mObbEventListenerRef == null) {
283 return null;
284 }
285 return mObbEventListenerRef.get();
286 }
287
Kenny Rootaf9d6672010-10-08 09:21:39 -0700288 void sendObbStateChanged(String path, int state) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700289 mHandler.obtainMessage(0, state, 0, path).sendToTarget();
San Mehatb1043402010-02-05 08:26:50 -0800290 }
291 }
292
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700293 /** {@hide} */
Jeff Sharkey50a05452015-04-29 11:24:52 -0700294 @Deprecated
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700295 public static StorageManager from(Context context) {
Jeff Sharkey50a05452015-04-29 11:24:52 -0700296 return context.getSystemService(StorageManager.class);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700297 }
298
San Mehatb1043402010-02-05 08:26:50 -0800299 /**
300 * Constructs a StorageManager object through which an application can
301 * can communicate with the systems mount service.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900302 *
Jeff Smitha45746e2012-07-19 14:19:24 -0500303 * @param tgtLooper The {@link android.os.Looper} which events will be received on.
San Mehatb1043402010-02-05 08:26:50 -0800304 *
305 * <p>Applications can get instance of this class by calling
306 * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
307 * of {@link android.content.Context#STORAGE_SERVICE}.
308 *
309 * @hide
310 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700311 public StorageManager(Context context, Looper looper) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700312 mContext = context;
313 mResolver = context.getContentResolver();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700314 mLooper = looper;
San Mehatb1043402010-02-05 08:26:50 -0800315 mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
316 if (mMountService == null) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700317 throw new IllegalStateException("Failed to find running mount service");
San Mehatb1043402010-02-05 08:26:50 -0800318 }
San Mehatb1043402010-02-05 08:26:50 -0800319 }
320
San Mehatb1043402010-02-05 08:26:50 -0800321 /**
322 * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}.
323 *
324 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
325 *
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800326 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800327 */
328 public void registerListener(StorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700329 synchronized (mDelegates) {
330 final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(listener,
331 mLooper);
332 try {
333 mMountService.registerListener(delegate);
334 } catch (RemoteException e) {
335 throw e.rethrowAsRuntimeException();
Chuanxia Dong6614bb62012-05-29 12:28:24 +0800336 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700337 mDelegates.add(delegate);
San Mehatb1043402010-02-05 08:26:50 -0800338 }
339 }
340
341 /**
342 * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}.
343 *
344 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
345 *
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800346 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800347 */
348 public void unregisterListener(StorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700349 synchronized (mDelegates) {
350 for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) {
351 final StorageEventListenerDelegate delegate = i.next();
352 if (delegate.mCallback == listener) {
353 try {
354 mMountService.unregisterListener(delegate);
355 } catch (RemoteException e) {
356 throw e.rethrowAsRuntimeException();
357 }
358 i.remove();
359 }
360 }
San Mehatb1043402010-02-05 08:26:50 -0800361 }
San Mehatb1043402010-02-05 08:26:50 -0800362 }
363
364 /**
365 * Enables USB Mass Storage (UMS) on the device.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800366 *
367 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800368 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700369 @Deprecated
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800370 public void enableUsbMassStorage() {
San Mehatb1043402010-02-05 08:26:50 -0800371 }
372
373 /**
374 * Disables USB Mass Storage (UMS) on the device.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800375 *
376 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800377 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700378 @Deprecated
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800379 public void disableUsbMassStorage() {
San Mehatb1043402010-02-05 08:26:50 -0800380 }
381
382 /**
383 * Query if a USB Mass Storage (UMS) host is connected.
384 * @return true if UMS host is connected.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800385 *
386 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800387 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700388 @Deprecated
San Mehatb1043402010-02-05 08:26:50 -0800389 public boolean isUsbMassStorageConnected() {
San Mehatb1043402010-02-05 08:26:50 -0800390 return false;
391 }
392
393 /**
394 * Query if a USB Mass Storage (UMS) is enabled on the device.
395 * @return true if UMS host is enabled.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800396 *
397 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800398 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700399 @Deprecated
San Mehatb1043402010-02-05 08:26:50 -0800400 public boolean isUsbMassStorageEnabled() {
San Mehatb1043402010-02-05 08:26:50 -0800401 return false;
402 }
Kenny Root02c87302010-07-01 08:10:18 -0700403
404 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700405 * Mount an Opaque Binary Blob (OBB) file. If a <code>key</code> is
406 * specified, it is supplied to the mounting process to be used in any
407 * encryption used in the OBB.
408 * <p>
Kenny Root05105f72010-09-22 17:29:43 -0700409 * The OBB will remain mounted for as long as the StorageManager reference
410 * is held by the application. As soon as this reference is lost, the OBBs
Kenny Rootaf9d6672010-10-08 09:21:39 -0700411 * in use will be unmounted. The {@link OnObbStateChangeListener} registered
412 * with this call will receive the success or failure of this operation.
Kenny Root05105f72010-09-22 17:29:43 -0700413 * <p>
Kenny Roota02b8b02010-08-05 16:14:17 -0700414 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
415 * file matches a package ID that is owned by the calling program's UID.
Kenny Root05105f72010-09-22 17:29:43 -0700416 * That is, shared UID applications can attempt to mount any other
Kenny Roota02b8b02010-08-05 16:14:17 -0700417 * application's OBB that shares its UID.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900418 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700419 * @param rawPath the path to the OBB file
Kenny Root05105f72010-09-22 17:29:43 -0700420 * @param key secret used to encrypt the OBB; may be <code>null</code> if no
421 * encryption was used on the OBB.
Kenny Rootaf9d6672010-10-08 09:21:39 -0700422 * @param listener will receive the success or failure of the operation
Kenny Roota02b8b02010-08-05 16:14:17 -0700423 * @return whether the mount call was successfully queued or not
Kenny Root02c87302010-07-01 08:10:18 -0700424 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700425 public boolean mountObb(String rawPath, String key, OnObbStateChangeListener listener) {
426 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
427 Preconditions.checkNotNull(listener, "listener cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700428
Kenny Root02c87302010-07-01 08:10:18 -0700429 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700430 final String canonicalPath = new File(rawPath).getCanonicalPath();
Kenny Rootaf9d6672010-10-08 09:21:39 -0700431 final int nonce = mObbActionListener.addListener(listener);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700432 mMountService.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce);
Kenny Roota02b8b02010-08-05 16:14:17 -0700433 return true;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700434 } catch (IOException e) {
435 throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e);
Kenny Root02c87302010-07-01 08:10:18 -0700436 } catch (RemoteException e) {
437 Log.e(TAG, "Failed to mount OBB", e);
438 }
439
440 return false;
441 }
442
443 /**
Kenny Root05105f72010-09-22 17:29:43 -0700444 * Unmount an Opaque Binary Blob (OBB) file asynchronously. If the
445 * <code>force</code> flag is true, it will kill any application needed to
446 * unmount the given OBB (even the calling application).
447 * <p>
Kenny Rootaf9d6672010-10-08 09:21:39 -0700448 * The {@link OnObbStateChangeListener} registered with this call will
449 * receive the success or failure of this operation.
Kenny Roota02b8b02010-08-05 16:14:17 -0700450 * <p>
451 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
452 * file matches a package ID that is owned by the calling program's UID.
453 * That is, shared UID applications can obtain access to any other
454 * application's OBB that shares its UID.
Kenny Root02ca31f2010-08-12 07:36:02 -0700455 * <p>
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900456 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700457 * @param rawPath path to the OBB file
Kenny Roota02b8b02010-08-05 16:14:17 -0700458 * @param force whether to kill any programs using this in order to unmount
459 * it
Kenny Rootaf9d6672010-10-08 09:21:39 -0700460 * @param listener will receive the success or failure of the operation
Kenny Roota02b8b02010-08-05 16:14:17 -0700461 * @return whether the unmount call was successfully queued or not
Kenny Root02c87302010-07-01 08:10:18 -0700462 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700463 public boolean unmountObb(String rawPath, boolean force, OnObbStateChangeListener listener) {
464 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
465 Preconditions.checkNotNull(listener, "listener cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700466
Kenny Root02c87302010-07-01 08:10:18 -0700467 try {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700468 final int nonce = mObbActionListener.addListener(listener);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700469 mMountService.unmountObb(rawPath, force, mObbActionListener, nonce);
Kenny Roota02b8b02010-08-05 16:14:17 -0700470 return true;
Kenny Root02c87302010-07-01 08:10:18 -0700471 } catch (RemoteException e) {
472 Log.e(TAG, "Failed to mount OBB", e);
473 }
474
475 return false;
476 }
477
Kenny Roota02b8b02010-08-05 16:14:17 -0700478 /**
479 * Check whether an Opaque Binary Blob (OBB) is mounted or not.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900480 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700481 * @param rawPath path to OBB image
Kenny Roota02b8b02010-08-05 16:14:17 -0700482 * @return true if OBB is mounted; false if not mounted or on error
483 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700484 public boolean isObbMounted(String rawPath) {
485 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700486
Kenny Root02c87302010-07-01 08:10:18 -0700487 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700488 return mMountService.isObbMounted(rawPath);
Kenny Root02c87302010-07-01 08:10:18 -0700489 } catch (RemoteException e) {
490 Log.e(TAG, "Failed to check if OBB is mounted", e);
491 }
492
493 return false;
494 }
495
496 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700497 * Check the mounted path of an Opaque Binary Blob (OBB) file. This will
498 * give you the path to where you can obtain access to the internals of the
499 * OBB.
Daichi Hirono9e8d9e22015-11-13 14:37:00 +0900500 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700501 * @param rawPath path to OBB image
Kenny Roota02b8b02010-08-05 16:14:17 -0700502 * @return absolute path to mounted OBB image data or <code>null</code> if
503 * not mounted or exception encountered trying to read status
Kenny Root02c87302010-07-01 08:10:18 -0700504 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700505 public String getMountedObbPath(String rawPath) {
506 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700507
Kenny Root02c87302010-07-01 08:10:18 -0700508 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700509 return mMountService.getMountedObbPath(rawPath);
Kenny Root02c87302010-07-01 08:10:18 -0700510 } catch (RemoteException e) {
511 Log.e(TAG, "Failed to find mounted path for OBB", e);
512 }
513
514 return null;
515 }
Mike Lockwoodd967f462011-03-24 08:12:30 -0700516
Jeff Sharkey48877892015-03-18 11:27:19 -0700517 /** {@hide} */
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700518 public @NonNull List<DiskInfo> getDisks() {
519 try {
520 return Arrays.asList(mMountService.getDisks());
521 } catch (RemoteException e) {
522 throw e.rethrowAsRuntimeException();
523 }
524 }
525
526 /** {@hide} */
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700527 public @Nullable DiskInfo findDiskById(String id) {
528 Preconditions.checkNotNull(id);
529 // TODO; go directly to service to make this faster
530 for (DiskInfo disk : getDisks()) {
531 if (Objects.equals(disk.id, id)) {
532 return disk;
533 }
534 }
535 return null;
536 }
537
538 /** {@hide} */
539 public @Nullable VolumeInfo findVolumeById(String id) {
540 Preconditions.checkNotNull(id);
541 // TODO; go directly to service to make this faster
542 for (VolumeInfo vol : getVolumes()) {
543 if (Objects.equals(vol.id, id)) {
544 return vol;
545 }
546 }
547 return null;
548 }
549
550 /** {@hide} */
551 public @Nullable VolumeInfo findVolumeByUuid(String fsUuid) {
552 Preconditions.checkNotNull(fsUuid);
553 // TODO; go directly to service to make this faster
554 for (VolumeInfo vol : getVolumes()) {
555 if (Objects.equals(vol.fsUuid, fsUuid)) {
556 return vol;
557 }
558 }
559 return null;
560 }
561
562 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700563 public @Nullable VolumeRecord findRecordByUuid(String fsUuid) {
564 Preconditions.checkNotNull(fsUuid);
565 // TODO; go directly to service to make this faster
566 for (VolumeRecord rec : getVolumeRecords()) {
567 if (Objects.equals(rec.fsUuid, fsUuid)) {
568 return rec;
569 }
570 }
571 return null;
572 }
573
574 /** {@hide} */
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700575 public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700576 if (emulatedVol != null) {
577 return findVolumeById(emulatedVol.getId().replace("emulated", "private"));
578 } else {
579 return null;
580 }
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700581 }
582
583 /** {@hide} */
584 public @Nullable VolumeInfo findEmulatedForPrivate(VolumeInfo privateVol) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700585 if (privateVol != null) {
586 return findVolumeById(privateVol.getId().replace("private", "emulated"));
587 } else {
588 return null;
589 }
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700590 }
591
592 /** {@hide} */
Jeff Sharkey50a05452015-04-29 11:24:52 -0700593 public @Nullable VolumeInfo findVolumeByQualifiedUuid(String volumeUuid) {
594 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
595 return findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL);
596 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
597 return getPrimaryPhysicalVolume();
598 } else {
599 return findVolumeByUuid(volumeUuid);
600 }
601 }
602
603 /** {@hide} */
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700604 public @NonNull List<VolumeInfo> getVolumes() {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700605 try {
606 return Arrays.asList(mMountService.getVolumes(0));
607 } catch (RemoteException e) {
608 throw e.rethrowAsRuntimeException();
609 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700610 }
611
612 /** {@hide} */
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700613 public @NonNull List<VolumeInfo> getWritablePrivateVolumes() {
614 try {
615 final ArrayList<VolumeInfo> res = new ArrayList<>();
616 for (VolumeInfo vol : mMountService.getVolumes(0)) {
617 if (vol.getType() == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) {
618 res.add(vol);
619 }
620 }
621 return res;
622 } catch (RemoteException e) {
623 throw e.rethrowAsRuntimeException();
624 }
625 }
626
627 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700628 public @NonNull List<VolumeRecord> getVolumeRecords() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700629 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700630 return Arrays.asList(mMountService.getVolumeRecords(0));
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700631 } catch (RemoteException e) {
632 throw e.rethrowAsRuntimeException();
633 }
634 }
635
636 /** {@hide} */
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700637 public @Nullable String getBestVolumeDescription(VolumeInfo vol) {
Jeff Sharkey50a05452015-04-29 11:24:52 -0700638 if (vol == null) return null;
639
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700640 // Nickname always takes precedence when defined
641 if (!TextUtils.isEmpty(vol.fsUuid)) {
642 final VolumeRecord rec = findRecordByUuid(vol.fsUuid);
Jeff Sharkeyc8406812015-05-04 12:04:09 -0700643 if (rec != null && !TextUtils.isEmpty(rec.nickname)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700644 return rec.nickname;
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700645 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700646 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700647
648 if (!TextUtils.isEmpty(vol.getDescription())) {
649 return vol.getDescription();
650 }
651
652 if (vol.disk != null) {
653 return vol.disk.getDescription();
654 }
655
656 return null;
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700657 }
658
659 /** {@hide} */
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700660 public @Nullable VolumeInfo getPrimaryPhysicalVolume() {
661 final List<VolumeInfo> vols = getVolumes();
662 for (VolumeInfo vol : vols) {
663 if (vol.isPrimaryPhysical()) {
664 return vol;
665 }
666 }
667 return null;
668 }
669
670 /** {@hide} */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700671 public void mount(String volId) {
672 try {
673 mMountService.mount(volId);
674 } catch (RemoteException e) {
675 throw e.rethrowAsRuntimeException();
676 }
677 }
678
679 /** {@hide} */
680 public void unmount(String volId) {
681 try {
682 mMountService.unmount(volId);
683 } catch (RemoteException e) {
684 throw e.rethrowAsRuntimeException();
685 }
686 }
687
688 /** {@hide} */
689 public void format(String volId) {
690 try {
691 mMountService.format(volId);
692 } catch (RemoteException e) {
693 throw e.rethrowAsRuntimeException();
694 }
695 }
696
697 /** {@hide} */
Jeff Sharkey9756d752015-05-14 21:07:42 -0700698 public long benchmark(String volId) {
699 try {
700 return mMountService.benchmark(volId);
701 } catch (RemoteException e) {
702 throw e.rethrowAsRuntimeException();
703 }
704 }
705
706 /** {@hide} */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700707 public void partitionPublic(String diskId) {
708 try {
709 mMountService.partitionPublic(diskId);
710 } catch (RemoteException e) {
711 throw e.rethrowAsRuntimeException();
712 }
713 }
714
715 /** {@hide} */
716 public void partitionPrivate(String diskId) {
717 try {
718 mMountService.partitionPrivate(diskId);
719 } catch (RemoteException e) {
720 throw e.rethrowAsRuntimeException();
721 }
722 }
723
724 /** {@hide} */
725 public void partitionMixed(String diskId, int ratio) {
726 try {
727 mMountService.partitionMixed(diskId, ratio);
728 } catch (RemoteException e) {
729 throw e.rethrowAsRuntimeException();
730 }
731 }
732
733 /** {@hide} */
Jeff Sharkeyb42d6942015-04-28 22:25:26 -0700734 public void wipeAdoptableDisks() {
735 // We only wipe devices in "adoptable" locations, which are in a
736 // long-term stable slot/location on the device, where apps have a
737 // reasonable chance of storing sensitive data. (Apps need to go through
738 // SAF to write to transient volumes.)
739 final List<DiskInfo> disks = getDisks();
740 for (DiskInfo disk : disks) {
741 final String diskId = disk.getId();
742 if (disk.isAdoptable()) {
743 Slog.d(TAG, "Found adoptable " + diskId + "; wiping");
744 try {
745 // TODO: switch to explicit wipe command when we have it,
746 // for now rely on the fact that vfat format does a wipe
747 mMountService.partitionPublic(diskId);
748 } catch (Exception e) {
749 Slog.w(TAG, "Failed to wipe " + diskId + ", but soldiering onward", e);
750 }
751 } else {
752 Slog.d(TAG, "Ignorning non-adoptable disk " + disk.getId());
753 }
754 }
755 }
756
757 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700758 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700759 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700760 mMountService.setVolumeNickname(fsUuid, nickname);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700761 } catch (RemoteException e) {
762 throw e.rethrowAsRuntimeException();
763 }
764 }
765
766 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700767 public void setVolumeInited(String fsUuid, boolean inited) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700768 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700769 mMountService.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0,
770 VolumeRecord.USER_FLAG_INITED);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700771 } catch (RemoteException e) {
772 throw e.rethrowAsRuntimeException();
773 }
774 }
775
776 /** {@hide} */
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700777 public void setVolumeSnoozed(String fsUuid, boolean snoozed) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700778 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700779 mMountService.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0,
780 VolumeRecord.USER_FLAG_SNOOZED);
781 } catch (RemoteException e) {
782 throw e.rethrowAsRuntimeException();
783 }
784 }
785
786 /** {@hide} */
787 public void forgetVolume(String fsUuid) {
788 try {
789 mMountService.forgetVolume(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700790 } catch (RemoteException e) {
791 throw e.rethrowAsRuntimeException();
792 }
793 }
794
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700795 /**
796 * This is not the API you're looking for.
797 *
798 * @see PackageManager#getPrimaryStorageCurrentVolume()
799 * @hide
800 */
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700801 public String getPrimaryStorageUuid() {
802 try {
803 return mMountService.getPrimaryStorageUuid();
804 } catch (RemoteException e) {
805 throw e.rethrowAsRuntimeException();
806 }
807 }
808
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700809 /**
810 * This is not the API you're looking for.
811 *
812 * @see PackageManager#movePrimaryStorage(VolumeInfo)
813 * @hide
814 */
815 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700816 try {
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700817 mMountService.setPrimaryStorageUuid(volumeUuid, callback);
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700818 } catch (RemoteException e) {
819 throw e.rethrowAsRuntimeException();
820 }
821 }
822
823 /** {@hide} */
Jeff Sharkey48877892015-03-18 11:27:19 -0700824 public @Nullable StorageVolume getStorageVolume(File file) {
825 return getStorageVolume(getVolumeList(), file);
826 }
827
828 /** {@hide} */
829 public static @Nullable StorageVolume getStorageVolume(File file, int userId) {
Jeff Sharkey46349872015-07-28 10:49:47 -0700830 return getStorageVolume(getVolumeList(userId, 0), file);
Jeff Sharkey48877892015-03-18 11:27:19 -0700831 }
832
833 /** {@hide} */
834 private static @Nullable StorageVolume getStorageVolume(StorageVolume[] volumes, File file) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700835 try {
Jeff Sharkey983294592015-07-13 10:25:31 -0700836 file = file.getCanonicalFile();
Jeff Sharkey48877892015-03-18 11:27:19 -0700837 } catch (IOException ignored) {
Jeff Sharkey983294592015-07-13 10:25:31 -0700838 return null;
Jeff Sharkey48877892015-03-18 11:27:19 -0700839 }
840 for (StorageVolume volume : volumes) {
Jeff Sharkey983294592015-07-13 10:25:31 -0700841 File volumeFile = volume.getPathFile();
842 try {
843 volumeFile = volumeFile.getCanonicalFile();
844 } catch (IOException ignored) {
845 continue;
Jeff Sharkey48877892015-03-18 11:27:19 -0700846 }
Jeff Sharkey983294592015-07-13 10:25:31 -0700847 if (FileUtils.contains(volumeFile, file)) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700848 return volume;
849 }
850 }
851 return null;
852 }
853
Mike Lockwoodd967f462011-03-24 08:12:30 -0700854 /**
855 * Gets the state of a volume via its mountpoint.
856 * @hide
857 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700858 @Deprecated
859 public @NonNull String getVolumeState(String mountPoint) {
860 final StorageVolume vol = getStorageVolume(new File(mountPoint));
861 if (vol != null) {
862 return vol.getState();
863 } else {
864 return Environment.MEDIA_UNKNOWN;
Mike Lockwoodd967f462011-03-24 08:12:30 -0700865 }
866 }
867
Felipe Leme04a5d402016-02-08 16:44:06 -0800868 /**
869 * Gets the list of shared/external storage volumes available to the current user.
870 *
871 * <p>It always contains the primary storage volume, plus any additional external volume(s)
872 * available in the device, such as SD cards or attached USB drives.
873 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700874 public @NonNull StorageVolume[] getVolumeList() {
Jeff Sharkey46349872015-07-28 10:49:47 -0700875 return getVolumeList(mContext.getUserId(), 0);
Jeff Sharkey48877892015-03-18 11:27:19 -0700876 }
877
878 /** {@hide} */
Jeff Sharkey46349872015-07-28 10:49:47 -0700879 public static @NonNull StorageVolume[] getVolumeList(int userId, int flags) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700880 final IMountService mountService = IMountService.Stub.asInterface(
881 ServiceManager.getService("mount"));
882 try {
Svetoslav7395cbf2015-07-15 15:58:01 -0700883 String packageName = ActivityThread.currentOpPackageName();
884 if (packageName == null) {
885 // Package name can be null if the activity thread is running but the app
886 // hasn't bound yet. In this case we fall back to the first package in the
887 // current UID. This works for runtime permissions as permission state is
888 // per UID and permission realted app ops are updated for all UID packages.
889 String[] packageNames = ActivityThread.getPackageManager().getPackagesForUid(
890 android.os.Process.myUid());
891 if (packageNames == null || packageNames.length <= 0) {
892 return new StorageVolume[0];
893 }
894 packageName = packageNames[0];
895 }
Jeff Sharkeycd654482016-01-08 17:42:11 -0700896 final int uid = ActivityThread.getPackageManager().getPackageUid(packageName,
Jeff Sharkeyc5967e92016-01-07 18:50:29 -0700897 PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
Svetoslav7395cbf2015-07-15 15:58:01 -0700898 if (uid <= 0) {
899 return new StorageVolume[0];
900 }
Jeff Sharkey46349872015-07-28 10:49:47 -0700901 return mountService.getVolumeList(uid, packageName, flags);
Jeff Sharkey48877892015-03-18 11:27:19 -0700902 } catch (RemoteException e) {
903 throw e.rethrowAsRuntimeException();
Mike Lockwoodd967f462011-03-24 08:12:30 -0700904 }
905 }
Mike Lockwood2f6a3882011-05-09 19:08:06 -0700906
907 /**
908 * Returns list of paths for all mountable volumes.
909 * @hide
910 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700911 @Deprecated
912 public @NonNull String[] getVolumePaths() {
Mike Lockwood2f6a3882011-05-09 19:08:06 -0700913 StorageVolume[] volumes = getVolumeList();
Mike Lockwood2f6a3882011-05-09 19:08:06 -0700914 int count = volumes.length;
915 String[] paths = new String[count];
916 for (int i = 0; i < count; i++) {
917 paths[i] = volumes[i].getPath();
918 }
919 return paths;
920 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700921
Felipe Leme04a5d402016-02-08 16:44:06 -0800922 /**
923 * Gets the primary shared/external storage volume available to the current user.
924 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700925 public @NonNull StorageVolume getPrimaryVolume() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700926 return getPrimaryVolume(getVolumeList());
927 }
928
929 /** {@hide} */
Jeff Sharkey48877892015-03-18 11:27:19 -0700930 public static @NonNull StorageVolume getPrimaryVolume(StorageVolume[] volumes) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700931 for (StorageVolume volume : volumes) {
932 if (volume.isPrimary()) {
933 return volume;
934 }
935 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700936 throw new IllegalStateException("Missing primary storage");
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700937 }
Jeff Sharkeybe722152013-02-15 16:56:38 -0800938
Jeff Sharkey48877892015-03-18 11:27:19 -0700939 /** {@hide} */
Jeff Sharkeybe722152013-02-15 16:56:38 -0800940 private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10;
941 private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500 * MB_IN_BYTES;
942 private static final long DEFAULT_FULL_THRESHOLD_BYTES = MB_IN_BYTES;
943
944 /**
Jeff Sharkey742e7902014-08-16 19:09:13 -0700945 * Return the number of available bytes until the given path is considered
946 * running low on storage.
947 *
948 * @hide
949 */
950 public long getStorageBytesUntilLow(File path) {
951 return path.getUsableSpace() - getStorageFullBytes(path);
952 }
953
954 /**
Jeff Sharkeybe722152013-02-15 16:56:38 -0800955 * Return the number of available bytes at which the given path is
956 * considered running low on storage.
957 *
958 * @hide
959 */
960 public long getStorageLowBytes(File path) {
961 final long lowPercent = Settings.Global.getInt(mResolver,
962 Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE);
963 final long lowBytes = (path.getTotalSpace() * lowPercent) / 100;
964
965 final long maxLowBytes = Settings.Global.getLong(mResolver,
966 Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES);
967
968 return Math.min(lowBytes, maxLowBytes);
969 }
970
971 /**
972 * Return the number of available bytes at which the given path is
973 * considered full.
974 *
975 * @hide
976 */
977 public long getStorageFullBytes(File path) {
978 return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
979 DEFAULT_FULL_THRESHOLD_BYTES);
980 }
Paul Lawrencee8fdc542014-05-28 07:14:17 -0700981
Jeff Sharkey50a05452015-04-29 11:24:52 -0700982 /** {@hide} */
Lenka Trochtovac4dd0212015-11-18 12:22:06 +0100983 public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
Paul Crowleybcf48ed2015-04-22 13:36:59 +0100984 try {
Lenka Trochtovac4dd0212015-11-18 12:22:06 +0100985 mMountService.createUserKey(userId, serialNumber, ephemeral);
Paul Crowleybcf48ed2015-04-22 13:36:59 +0100986 } catch (RemoteException e) {
987 throw e.rethrowAsRuntimeException();
988 }
989 }
990
991 /** {@hide} */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800992 public void destroyUserKey(int userId) {
Paul Crowley7ec733f2015-05-19 12:42:00 +0100993 try {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800994 mMountService.destroyUserKey(userId);
995 } catch (RemoteException e) {
996 throw e.rethrowAsRuntimeException();
997 }
998 }
999
1000 /** {@hide} */
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001001 public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001002 try {
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00001003 mMountService.unlockUserKey(userId, serialNumber, token, secret);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001004 } catch (RemoteException e) {
1005 throw e.rethrowAsRuntimeException();
1006 }
1007 }
1008
1009 /** {@hide} */
1010 public void lockUserKey(int userId) {
1011 try {
1012 mMountService.lockUserKey(userId);
1013 } catch (RemoteException e) {
1014 throw e.rethrowAsRuntimeException();
1015 }
1016 }
1017
1018 /** {@hide} */
Jeff Sharkey47f71082016-02-01 17:03:54 -07001019 public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001020 try {
Jeff Sharkey47f71082016-02-01 17:03:54 -07001021 mMountService.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08001022 } catch (RemoteException e) {
1023 throw e.rethrowAsRuntimeException();
1024 }
1025 }
1026
1027 /** {@hide} */
1028 public boolean isUserKeyUnlocked(int userId) {
1029 try {
1030 return mMountService.isUserKeyUnlocked(userId);
Paul Crowley7ec733f2015-05-19 12:42:00 +01001031 } catch (RemoteException e) {
1032 throw e.rethrowAsRuntimeException();
1033 }
1034 }
1035
1036 /** {@hide} */
Jeff Sharkeyba512352015-11-12 20:17:45 -08001037 public static boolean isFileBasedEncryptionEnabled() {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001038 return isNativeFileBasedEncryptionEnabled() || isEmulatedFileBasedEncryptionEnabled();
1039 }
1040
1041 /** {@hide} */
1042 public static boolean isNativeFileBasedEncryptionEnabled() {
1043 return "file".equals(SystemProperties.get("ro.crypto.type", "none"));
1044 }
1045
1046 /** {@hide} */
1047 public static boolean isEmulatedFileBasedEncryptionEnabled() {
1048 return SystemProperties.getBoolean(StorageManager.PROP_EMULATE_FBE, false);
Clara Bayarri965da392015-10-28 17:53:53 +00001049 }
1050
1051 /** {@hide} */
Jeff Sharkey50a05452015-04-29 11:24:52 -07001052 public static File maybeTranslateEmulatedPathToInternal(File path) {
1053 final IMountService mountService = IMountService.Stub.asInterface(
1054 ServiceManager.getService("mount"));
1055 try {
1056 final VolumeInfo[] vols = mountService.getVolumes(0);
1057 for (VolumeInfo vol : vols) {
1058 if ((vol.getType() == VolumeInfo.TYPE_EMULATED
1059 || vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.isMountedReadable()) {
1060 final File internalPath = FileUtils.rewriteAfterRename(vol.getPath(),
1061 vol.getInternalPath(), path);
Marco Nelissenaa411032015-07-14 08:22:47 -07001062 if (internalPath != null && internalPath.exists()) {
Jeff Sharkey50a05452015-04-29 11:24:52 -07001063 return internalPath;
1064 }
1065 }
1066 }
1067 } catch (RemoteException ignored) {
1068 }
1069 return path;
1070 }
1071
Daichi Hirono9e8d9e22015-11-13 14:37:00 +09001072 /** {@hide} */
1073 public ParcelFileDescriptor mountAppFuse(String name) {
1074 try {
1075 return mMountService.mountAppFuse(name);
1076 } catch (RemoteException e) {
1077 throw e.rethrowAsRuntimeException();
1078 }
1079 }
1080
Paul Lawrencee8fdc542014-05-28 07:14:17 -07001081 /// Consts to match the password types in cryptfs.h
1082 /** @hide */
1083 public static final int CRYPT_TYPE_PASSWORD = 0;
1084 /** @hide */
1085 public static final int CRYPT_TYPE_DEFAULT = 1;
1086 /** @hide */
1087 public static final int CRYPT_TYPE_PATTERN = 2;
1088 /** @hide */
1089 public static final int CRYPT_TYPE_PIN = 3;
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001090
1091 // Constants for the data available via MountService.getField.
1092 /** @hide */
1093 public static final String SYSTEM_LOCALE_KEY = "SystemLocale";
1094 /** @hide */
1095 public static final String OWNER_INFO_KEY = "OwnerInfo";
1096 /** @hide */
1097 public static final String PATTERN_VISIBLE_KEY = "PatternVisible";
Paul Lawrenced8fdb332015-05-18 13:26:11 -07001098 /** @hide */
1099 public static final String PASSWORD_VISIBLE_KEY = "PasswordVisible";
San Mehatb1043402010-02-05 08:26:50 -08001100}