blob: f101352294d18cb38ee56a8b92fa5fd5c25d0dcf [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;
Jeff Sharkeybe722152013-02-15 16:56:38 -080023import android.content.ContentResolver;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070024import android.content.Context;
Mike Lockwoodcba928c2011-08-17 15:58:52 -070025import android.os.Environment;
Jeff Sharkey48877892015-03-18 11:27:19 -070026import android.os.FileUtils;
San Mehatb1043402010-02-05 08:26:50 -080027import android.os.Handler;
Kenny Roota02b8b02010-08-05 16:14:17 -070028import android.os.Looper;
San Mehatb1043402010-02-05 08:26:50 -080029import android.os.Message;
Kenny Roota02b8b02010-08-05 16:14:17 -070030import android.os.RemoteException;
San Mehatb1043402010-02-05 08:26:50 -080031import android.os.ServiceManager;
Jeff Sharkeybe722152013-02-15 16:56:38 -080032import android.provider.Settings;
Jeff Sharkey59d577a2015-04-11 21:27:21 -070033import android.text.TextUtils;
San Mehatb1043402010-02-05 08:26:50 -080034import android.util.Log;
Kenny Rootaf9d6672010-10-08 09:21:39 -070035import android.util.SparseArray;
San Mehatb1043402010-02-05 08:26:50 -080036
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070037import com.android.internal.os.SomeArgs;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -070038import com.android.internal.util.Preconditions;
39
40import java.io.File;
41import java.io.IOException;
Kenny Root05105f72010-09-22 17:29:43 -070042import java.lang.ref.WeakReference;
San Mehatb1043402010-02-05 08:26:50 -080043import java.util.ArrayList;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070044import java.util.Arrays;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070045import java.util.Iterator;
Kenny Root05105f72010-09-22 17:29:43 -070046import java.util.List;
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -070047import java.util.Objects;
Kenny Rootaf9d6672010-10-08 09:21:39 -070048import java.util.concurrent.atomic.AtomicInteger;
San Mehatb1043402010-02-05 08:26:50 -080049
50/**
Kenny Root05105f72010-09-22 17:29:43 -070051 * StorageManager is the interface to the systems storage service. The storage
52 * manager handles storage-related items such as Opaque Binary Blobs (OBBs).
53 * <p>
54 * OBBs contain a filesystem that maybe be encrypted on disk and mounted
55 * on-demand from an application. OBBs are a good way of providing large amounts
56 * of binary assets without packaging them into APKs as they may be multiple
57 * gigabytes in size. However, due to their size, they're most likely stored in
58 * a shared storage pool accessible from all programs. The system does not
59 * guarantee the security of the OBB file itself: if any program modifies the
60 * OBB, there is no guarantee that a read from that OBB will produce the
61 * expected output.
62 * <p>
San Mehatb1043402010-02-05 08:26:50 -080063 * Get an instance of this class by calling
Kenny Root05105f72010-09-22 17:29:43 -070064 * {@link android.content.Context#getSystemService(java.lang.String)} with an
65 * argument of {@link android.content.Context#STORAGE_SERVICE}.
San Mehatb1043402010-02-05 08:26:50 -080066 */
Jeff Sharkeybe722152013-02-15 16:56:38 -080067public class StorageManager {
San Mehatb1043402010-02-05 08:26:50 -080068 private static final String TAG = "StorageManager";
69
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070070 /** {@hide} */
71 public static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical";
Jeff Sharkey74acbbb2015-04-21 12:14:03 -070072 /** {@hide} */
73 public static final String PROP_FORCE_ADOPTABLE = "persist.fw.force_adoptable";
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070074
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070075 /** {@hide} */
76 public static final int FLAG_ALL_METADATA = 1 << 0;
77
Jeff Sharkey48877892015-03-18 11:27:19 -070078 private final Context mContext;
Jeff Sharkeybe722152013-02-15 16:56:38 -080079 private final ContentResolver mResolver;
80
Jeff Sharkeybe722152013-02-15 16:56:38 -080081 private final IMountService mMountService;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070082 private final Looper mLooper;
83 private final AtomicInteger mNextNonce = new AtomicInteger(0);
San Mehatb1043402010-02-05 08:26:50 -080084
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070085 private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>();
San Mehatb1043402010-02-05 08:26:50 -080086
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070087 private static class StorageEventListenerDelegate extends IMountServiceListener.Stub implements
88 Handler.Callback {
89 private static final int MSG_STORAGE_STATE_CHANGED = 1;
90 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070091 private static final int MSG_VOLUME_METADATA_CHANGED = 3;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -070092 private static final int MSG_DISK_UNSUPPORTED = 4;
San Mehatb1043402010-02-05 08:26:50 -080093
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070094 final StorageEventListener mCallback;
95 final Handler mHandler;
Kenny Rootaf9d6672010-10-08 09:21:39 -070096
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070097 public StorageEventListenerDelegate(StorageEventListener callback, Looper looper) {
98 mCallback = callback;
99 mHandler = new Handler(looper, this);
San Mehatb1043402010-02-05 08:26:50 -0800100 }
101
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700102 @Override
103 public boolean handleMessage(Message msg) {
104 final SomeArgs args = (SomeArgs) msg.obj;
105 switch (msg.what) {
106 case MSG_STORAGE_STATE_CHANGED:
107 mCallback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
108 (String) args.arg3);
109 args.recycle();
110 return true;
111 case MSG_VOLUME_STATE_CHANGED:
112 mCallback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
113 args.recycle();
114 return true;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700115 case MSG_VOLUME_METADATA_CHANGED:
116 mCallback.onVolumeMetadataChanged((VolumeInfo) args.arg1);
117 args.recycle();
118 return true;
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700119 case MSG_DISK_UNSUPPORTED:
120 mCallback.onDiskUnsupported((DiskInfo) args.arg1);
121 args.recycle();
122 return true;
San Mehatb1043402010-02-05 08:26:50 -0800123 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700124 args.recycle();
125 return false;
126 }
127
128 @Override
129 public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException {
130 // Ignored
131 }
132
133 @Override
134 public void onStorageStateChanged(String path, String oldState, String newState) {
135 final SomeArgs args = SomeArgs.obtain();
136 args.arg1 = path;
137 args.arg2 = oldState;
138 args.arg3 = newState;
139 mHandler.obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
140 }
141
142 @Override
143 public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
144 final SomeArgs args = SomeArgs.obtain();
145 args.arg1 = vol;
146 args.argi2 = oldState;
147 args.argi3 = newState;
148 mHandler.obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
San Mehatb1043402010-02-05 08:26:50 -0800149 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700150
151 @Override
152 public void onVolumeMetadataChanged(VolumeInfo vol) {
153 final SomeArgs args = SomeArgs.obtain();
154 args.arg1 = vol;
155 mHandler.obtainMessage(MSG_VOLUME_METADATA_CHANGED, args).sendToTarget();
156 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700157
158 @Override
159 public void onDiskUnsupported(DiskInfo disk) {
160 final SomeArgs args = SomeArgs.obtain();
161 args.arg1 = disk;
162 mHandler.obtainMessage(MSG_DISK_UNSUPPORTED, args).sendToTarget();
163 }
San Mehatb1043402010-02-05 08:26:50 -0800164 }
165
166 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700167 * Binder listener for OBB action results.
168 */
Kenny Root05105f72010-09-22 17:29:43 -0700169 private final ObbActionListener mObbActionListener = new ObbActionListener();
170
171 private class ObbActionListener extends IObbActionListener.Stub {
Gilles Debunne37051cd2011-05-25 16:27:13 -0700172 @SuppressWarnings("hiding")
Kenny Rootaf9d6672010-10-08 09:21:39 -0700173 private SparseArray<ObbListenerDelegate> mListeners = new SparseArray<ObbListenerDelegate>();
Kenny Root05105f72010-09-22 17:29:43 -0700174
Kenny Roota02b8b02010-08-05 16:14:17 -0700175 @Override
Gilles Debunne37051cd2011-05-25 16:27:13 -0700176 public void onObbResult(String filename, int nonce, int status) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700177 final ObbListenerDelegate delegate;
Kenny Root05105f72010-09-22 17:29:43 -0700178 synchronized (mListeners) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700179 delegate = mListeners.get(nonce);
180 if (delegate != null) {
181 mListeners.remove(nonce);
Kenny Root05105f72010-09-22 17:29:43 -0700182 }
183 }
Kenny Rootaf9d6672010-10-08 09:21:39 -0700184
185 if (delegate != null) {
186 delegate.sendObbStateChanged(filename, status);
187 }
Kenny Root05105f72010-09-22 17:29:43 -0700188 }
189
Kenny Rootaf9d6672010-10-08 09:21:39 -0700190 public int addListener(OnObbStateChangeListener listener) {
191 final ObbListenerDelegate delegate = new ObbListenerDelegate(listener);
Kenny Root05105f72010-09-22 17:29:43 -0700192
193 synchronized (mListeners) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700194 mListeners.put(delegate.nonce, delegate);
Kenny Root05105f72010-09-22 17:29:43 -0700195 }
Kenny Rootaf9d6672010-10-08 09:21:39 -0700196
197 return delegate.nonce;
Kenny Root05105f72010-09-22 17:29:43 -0700198 }
199 }
200
Kenny Rootaf9d6672010-10-08 09:21:39 -0700201 private int getNextNonce() {
202 return mNextNonce.getAndIncrement();
203 }
204
Kenny Root05105f72010-09-22 17:29:43 -0700205 /**
206 * Private class containing sender and receiver code for StorageEvents.
207 */
208 private class ObbListenerDelegate {
209 private final WeakReference<OnObbStateChangeListener> mObbEventListenerRef;
210 private final Handler mHandler;
211
Kenny Rootaf9d6672010-10-08 09:21:39 -0700212 private final int nonce;
213
Kenny Root05105f72010-09-22 17:29:43 -0700214 ObbListenerDelegate(OnObbStateChangeListener listener) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700215 nonce = getNextNonce();
Kenny Root05105f72010-09-22 17:29:43 -0700216 mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700217 mHandler = new Handler(mLooper) {
Kenny Root05105f72010-09-22 17:29:43 -0700218 @Override
219 public void handleMessage(Message msg) {
Gilles Debunne37051cd2011-05-25 16:27:13 -0700220 final OnObbStateChangeListener changeListener = getListener();
221 if (changeListener == null) {
Kenny Root05105f72010-09-22 17:29:43 -0700222 return;
223 }
224
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700225 changeListener.onObbStateChange((String) msg.obj, msg.arg1);
Kenny Root05105f72010-09-22 17:29:43 -0700226 }
227 };
228 }
229
230 OnObbStateChangeListener getListener() {
231 if (mObbEventListenerRef == null) {
232 return null;
233 }
234 return mObbEventListenerRef.get();
235 }
236
Kenny Rootaf9d6672010-10-08 09:21:39 -0700237 void sendObbStateChanged(String path, int state) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700238 mHandler.obtainMessage(0, state, 0, path).sendToTarget();
San Mehatb1043402010-02-05 08:26:50 -0800239 }
240 }
241
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700242 /** {@hide} */
243 public static StorageManager from(Context context) {
244 return (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
245 }
246
San Mehatb1043402010-02-05 08:26:50 -0800247 /**
248 * Constructs a StorageManager object through which an application can
249 * can communicate with the systems mount service.
250 *
Jeff Smitha45746e2012-07-19 14:19:24 -0500251 * @param tgtLooper The {@link android.os.Looper} which events will be received on.
San Mehatb1043402010-02-05 08:26:50 -0800252 *
253 * <p>Applications can get instance of this class by calling
254 * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
255 * of {@link android.content.Context#STORAGE_SERVICE}.
256 *
257 * @hide
258 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700259 public StorageManager(Context context, Looper looper) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700260 mContext = context;
261 mResolver = context.getContentResolver();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700262 mLooper = looper;
San Mehatb1043402010-02-05 08:26:50 -0800263 mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
264 if (mMountService == null) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700265 throw new IllegalStateException("Failed to find running mount service");
San Mehatb1043402010-02-05 08:26:50 -0800266 }
San Mehatb1043402010-02-05 08:26:50 -0800267 }
268
San Mehatb1043402010-02-05 08:26:50 -0800269 /**
270 * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}.
271 *
272 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
273 *
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800274 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800275 */
276 public void registerListener(StorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700277 synchronized (mDelegates) {
278 final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(listener,
279 mLooper);
280 try {
281 mMountService.registerListener(delegate);
282 } catch (RemoteException e) {
283 throw e.rethrowAsRuntimeException();
Chuanxia Dong6614bb62012-05-29 12:28:24 +0800284 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700285 mDelegates.add(delegate);
San Mehatb1043402010-02-05 08:26:50 -0800286 }
287 }
288
289 /**
290 * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}.
291 *
292 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
293 *
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800294 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800295 */
296 public void unregisterListener(StorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700297 synchronized (mDelegates) {
298 for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) {
299 final StorageEventListenerDelegate delegate = i.next();
300 if (delegate.mCallback == listener) {
301 try {
302 mMountService.unregisterListener(delegate);
303 } catch (RemoteException e) {
304 throw e.rethrowAsRuntimeException();
305 }
306 i.remove();
307 }
308 }
San Mehatb1043402010-02-05 08:26:50 -0800309 }
San Mehatb1043402010-02-05 08:26:50 -0800310 }
311
312 /**
313 * Enables USB Mass Storage (UMS) on the device.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800314 *
315 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800316 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700317 @Deprecated
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800318 public void enableUsbMassStorage() {
San Mehatb1043402010-02-05 08:26:50 -0800319 }
320
321 /**
322 * Disables USB Mass Storage (UMS) on the device.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800323 *
324 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800325 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700326 @Deprecated
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800327 public void disableUsbMassStorage() {
San Mehatb1043402010-02-05 08:26:50 -0800328 }
329
330 /**
331 * Query if a USB Mass Storage (UMS) host is connected.
332 * @return true if UMS host is connected.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800333 *
334 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800335 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700336 @Deprecated
San Mehatb1043402010-02-05 08:26:50 -0800337 public boolean isUsbMassStorageConnected() {
San Mehatb1043402010-02-05 08:26:50 -0800338 return false;
339 }
340
341 /**
342 * Query if a USB Mass Storage (UMS) is enabled on the device.
343 * @return true if UMS host is enabled.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800344 *
345 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800346 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700347 @Deprecated
San Mehatb1043402010-02-05 08:26:50 -0800348 public boolean isUsbMassStorageEnabled() {
San Mehatb1043402010-02-05 08:26:50 -0800349 return false;
350 }
Kenny Root02c87302010-07-01 08:10:18 -0700351
352 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700353 * Mount an Opaque Binary Blob (OBB) file. If a <code>key</code> is
354 * specified, it is supplied to the mounting process to be used in any
355 * encryption used in the OBB.
356 * <p>
Kenny Root05105f72010-09-22 17:29:43 -0700357 * The OBB will remain mounted for as long as the StorageManager reference
358 * is held by the application. As soon as this reference is lost, the OBBs
Kenny Rootaf9d6672010-10-08 09:21:39 -0700359 * in use will be unmounted. The {@link OnObbStateChangeListener} registered
360 * with this call will receive the success or failure of this operation.
Kenny Root05105f72010-09-22 17:29:43 -0700361 * <p>
Kenny Roota02b8b02010-08-05 16:14:17 -0700362 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
363 * file matches a package ID that is owned by the calling program's UID.
Kenny Root05105f72010-09-22 17:29:43 -0700364 * That is, shared UID applications can attempt to mount any other
Kenny Roota02b8b02010-08-05 16:14:17 -0700365 * application's OBB that shares its UID.
366 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700367 * @param rawPath the path to the OBB file
Kenny Root05105f72010-09-22 17:29:43 -0700368 * @param key secret used to encrypt the OBB; may be <code>null</code> if no
369 * encryption was used on the OBB.
Kenny Rootaf9d6672010-10-08 09:21:39 -0700370 * @param listener will receive the success or failure of the operation
Kenny Roota02b8b02010-08-05 16:14:17 -0700371 * @return whether the mount call was successfully queued or not
Kenny Root02c87302010-07-01 08:10:18 -0700372 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700373 public boolean mountObb(String rawPath, String key, OnObbStateChangeListener listener) {
374 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
375 Preconditions.checkNotNull(listener, "listener cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700376
Kenny Root02c87302010-07-01 08:10:18 -0700377 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700378 final String canonicalPath = new File(rawPath).getCanonicalPath();
Kenny Rootaf9d6672010-10-08 09:21:39 -0700379 final int nonce = mObbActionListener.addListener(listener);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700380 mMountService.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce);
Kenny Roota02b8b02010-08-05 16:14:17 -0700381 return true;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700382 } catch (IOException e) {
383 throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e);
Kenny Root02c87302010-07-01 08:10:18 -0700384 } catch (RemoteException e) {
385 Log.e(TAG, "Failed to mount OBB", e);
386 }
387
388 return false;
389 }
390
391 /**
Kenny Root05105f72010-09-22 17:29:43 -0700392 * Unmount an Opaque Binary Blob (OBB) file asynchronously. If the
393 * <code>force</code> flag is true, it will kill any application needed to
394 * unmount the given OBB (even the calling application).
395 * <p>
Kenny Rootaf9d6672010-10-08 09:21:39 -0700396 * The {@link OnObbStateChangeListener} registered with this call will
397 * receive the success or failure of this operation.
Kenny Roota02b8b02010-08-05 16:14:17 -0700398 * <p>
399 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
400 * file matches a package ID that is owned by the calling program's UID.
401 * That is, shared UID applications can obtain access to any other
402 * application's OBB that shares its UID.
Kenny Root02ca31f2010-08-12 07:36:02 -0700403 * <p>
Kenny Roota02b8b02010-08-05 16:14:17 -0700404 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700405 * @param rawPath path to the OBB file
Kenny Roota02b8b02010-08-05 16:14:17 -0700406 * @param force whether to kill any programs using this in order to unmount
407 * it
Kenny Rootaf9d6672010-10-08 09:21:39 -0700408 * @param listener will receive the success or failure of the operation
Kenny Roota02b8b02010-08-05 16:14:17 -0700409 * @return whether the unmount call was successfully queued or not
Kenny Root02c87302010-07-01 08:10:18 -0700410 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700411 public boolean unmountObb(String rawPath, boolean force, OnObbStateChangeListener listener) {
412 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
413 Preconditions.checkNotNull(listener, "listener cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700414
Kenny Root02c87302010-07-01 08:10:18 -0700415 try {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700416 final int nonce = mObbActionListener.addListener(listener);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700417 mMountService.unmountObb(rawPath, force, mObbActionListener, nonce);
Kenny Roota02b8b02010-08-05 16:14:17 -0700418 return true;
Kenny Root02c87302010-07-01 08:10:18 -0700419 } catch (RemoteException e) {
420 Log.e(TAG, "Failed to mount OBB", e);
421 }
422
423 return false;
424 }
425
Kenny Roota02b8b02010-08-05 16:14:17 -0700426 /**
427 * Check whether an Opaque Binary Blob (OBB) is mounted or not.
428 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700429 * @param rawPath path to OBB image
Kenny Roota02b8b02010-08-05 16:14:17 -0700430 * @return true if OBB is mounted; false if not mounted or on error
431 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700432 public boolean isObbMounted(String rawPath) {
433 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700434
Kenny Root02c87302010-07-01 08:10:18 -0700435 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700436 return mMountService.isObbMounted(rawPath);
Kenny Root02c87302010-07-01 08:10:18 -0700437 } catch (RemoteException e) {
438 Log.e(TAG, "Failed to check if OBB is mounted", e);
439 }
440
441 return false;
442 }
443
444 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700445 * Check the mounted path of an Opaque Binary Blob (OBB) file. This will
446 * give you the path to where you can obtain access to the internals of the
447 * OBB.
448 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700449 * @param rawPath path to OBB image
Kenny Roota02b8b02010-08-05 16:14:17 -0700450 * @return absolute path to mounted OBB image data or <code>null</code> if
451 * not mounted or exception encountered trying to read status
Kenny Root02c87302010-07-01 08:10:18 -0700452 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700453 public String getMountedObbPath(String rawPath) {
454 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700455
Kenny Root02c87302010-07-01 08:10:18 -0700456 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700457 return mMountService.getMountedObbPath(rawPath);
Kenny Root02c87302010-07-01 08:10:18 -0700458 } catch (RemoteException e) {
459 Log.e(TAG, "Failed to find mounted path for OBB", e);
460 }
461
462 return null;
463 }
Mike Lockwoodd967f462011-03-24 08:12:30 -0700464
Jeff Sharkey48877892015-03-18 11:27:19 -0700465 /** {@hide} */
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700466 public @NonNull List<DiskInfo> getDisks() {
467 try {
468 return Arrays.asList(mMountService.getDisks());
469 } catch (RemoteException e) {
470 throw e.rethrowAsRuntimeException();
471 }
472 }
473
474 /** {@hide} */
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700475 public @Nullable DiskInfo findDiskById(String id) {
476 Preconditions.checkNotNull(id);
477 // TODO; go directly to service to make this faster
478 for (DiskInfo disk : getDisks()) {
479 if (Objects.equals(disk.id, id)) {
480 return disk;
481 }
482 }
483 return null;
484 }
485
486 /** {@hide} */
487 public @Nullable VolumeInfo findVolumeById(String id) {
488 Preconditions.checkNotNull(id);
489 // TODO; go directly to service to make this faster
490 for (VolumeInfo vol : getVolumes()) {
491 if (Objects.equals(vol.id, id)) {
492 return vol;
493 }
494 }
495 return null;
496 }
497
498 /** {@hide} */
499 public @Nullable VolumeInfo findVolumeByUuid(String fsUuid) {
500 Preconditions.checkNotNull(fsUuid);
501 // TODO; go directly to service to make this faster
502 for (VolumeInfo vol : getVolumes()) {
503 if (Objects.equals(vol.fsUuid, fsUuid)) {
504 return vol;
505 }
506 }
507 return null;
508 }
509
510 /** {@hide} */
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700511 public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) {
512 return findVolumeById(emulatedVol.getId().replace("emulated", "private"));
513 }
514
515 /** {@hide} */
516 public @Nullable VolumeInfo findEmulatedForPrivate(VolumeInfo privateVol) {
517 return findVolumeById(privateVol.getId().replace("private", "emulated"));
518 }
519
520 /** {@hide} */
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700521 public @NonNull List<VolumeInfo> getVolumes() {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700522 return getVolumes(0);
523 }
524
525 /** {@hide} */
526 public @NonNull List<VolumeInfo> getVolumes(int flags) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700527 try {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700528 return Arrays.asList(mMountService.getVolumes(flags));
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700529 } catch (RemoteException e) {
530 throw e.rethrowAsRuntimeException();
531 }
532 }
533
534 /** {@hide} */
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700535 public @Nullable String getBestVolumeDescription(VolumeInfo vol) {
536 String descrip = vol.getDescription();
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700537
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700538 if (vol.disk != null) {
539 if (TextUtils.isEmpty(descrip)) {
540 descrip = vol.disk.getDescription();
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700541 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700542 }
543
544 return descrip;
545 }
546
547 /** {@hide} */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700548 public void mount(String volId) {
549 try {
550 mMountService.mount(volId);
551 } catch (RemoteException e) {
552 throw e.rethrowAsRuntimeException();
553 }
554 }
555
556 /** {@hide} */
557 public void unmount(String volId) {
558 try {
559 mMountService.unmount(volId);
560 } catch (RemoteException e) {
561 throw e.rethrowAsRuntimeException();
562 }
563 }
564
565 /** {@hide} */
566 public void format(String volId) {
567 try {
568 mMountService.format(volId);
569 } catch (RemoteException e) {
570 throw e.rethrowAsRuntimeException();
571 }
572 }
573
574 /** {@hide} */
575 public void partitionPublic(String diskId) {
576 try {
577 mMountService.partitionPublic(diskId);
578 } catch (RemoteException e) {
579 throw e.rethrowAsRuntimeException();
580 }
581 }
582
583 /** {@hide} */
584 public void partitionPrivate(String diskId) {
585 try {
586 mMountService.partitionPrivate(diskId);
587 } catch (RemoteException e) {
588 throw e.rethrowAsRuntimeException();
589 }
590 }
591
592 /** {@hide} */
593 public void partitionMixed(String diskId, int ratio) {
594 try {
595 mMountService.partitionMixed(diskId, ratio);
596 } catch (RemoteException e) {
597 throw e.rethrowAsRuntimeException();
598 }
599 }
600
601 /** {@hide} */
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700602 public void setVolumeNickname(String volId, String nickname) {
603 try {
604 mMountService.setVolumeNickname(volId, nickname);
605 } catch (RemoteException e) {
606 throw e.rethrowAsRuntimeException();
607 }
608 }
609
610 /** {@hide} */
611 public void setVolumeInited(String volId, boolean inited) {
612 try {
613 mMountService.setVolumeUserFlags(volId, inited ? VolumeInfo.USER_FLAG_INITED : 0,
614 VolumeInfo.USER_FLAG_INITED);
615 } catch (RemoteException e) {
616 throw e.rethrowAsRuntimeException();
617 }
618 }
619
620 /** {@hide} */
621 public void setVolumeSnoozed(String volId, boolean snoozed) {
622 try {
623 mMountService.setVolumeUserFlags(volId, snoozed ? VolumeInfo.USER_FLAG_SNOOZED : 0,
624 VolumeInfo.USER_FLAG_SNOOZED);
625 } catch (RemoteException e) {
626 throw e.rethrowAsRuntimeException();
627 }
628 }
629
630 /** {@hide} */
Jeff Sharkey48877892015-03-18 11:27:19 -0700631 public @Nullable StorageVolume getStorageVolume(File file) {
632 return getStorageVolume(getVolumeList(), file);
633 }
634
635 /** {@hide} */
636 public static @Nullable StorageVolume getStorageVolume(File file, int userId) {
637 return getStorageVolume(getVolumeList(userId), file);
638 }
639
640 /** {@hide} */
641 private static @Nullable StorageVolume getStorageVolume(StorageVolume[] volumes, File file) {
642 File canonicalFile = null;
643 try {
644 canonicalFile = file.getCanonicalFile();
645 } catch (IOException ignored) {
646 canonicalFile = null;
647 }
648 for (StorageVolume volume : volumes) {
649 if (volume.getPathFile().equals(file)) {
650 return volume;
651 }
652 if (FileUtils.contains(volume.getPathFile(), canonicalFile)) {
653 return volume;
654 }
655 }
656 return null;
657 }
658
Mike Lockwoodd967f462011-03-24 08:12:30 -0700659 /**
660 * Gets the state of a volume via its mountpoint.
661 * @hide
662 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700663 @Deprecated
664 public @NonNull String getVolumeState(String mountPoint) {
665 final StorageVolume vol = getStorageVolume(new File(mountPoint));
666 if (vol != null) {
667 return vol.getState();
668 } else {
669 return Environment.MEDIA_UNKNOWN;
Mike Lockwoodd967f462011-03-24 08:12:30 -0700670 }
671 }
672
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700673 /** {@hide} */
Jeff Sharkey48877892015-03-18 11:27:19 -0700674 public @NonNull StorageVolume[] getVolumeList() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700675 return getVolumeList(mContext.getUserId());
Jeff Sharkey48877892015-03-18 11:27:19 -0700676 }
677
678 /** {@hide} */
679 public static @NonNull StorageVolume[] getVolumeList(int userId) {
680 final IMountService mountService = IMountService.Stub.asInterface(
681 ServiceManager.getService("mount"));
682 try {
683 return mountService.getVolumeList(userId);
684 } catch (RemoteException e) {
685 throw e.rethrowAsRuntimeException();
Mike Lockwoodd967f462011-03-24 08:12:30 -0700686 }
687 }
Mike Lockwood2f6a3882011-05-09 19:08:06 -0700688
689 /**
690 * Returns list of paths for all mountable volumes.
691 * @hide
692 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700693 @Deprecated
694 public @NonNull String[] getVolumePaths() {
Mike Lockwood2f6a3882011-05-09 19:08:06 -0700695 StorageVolume[] volumes = getVolumeList();
Mike Lockwood2f6a3882011-05-09 19:08:06 -0700696 int count = volumes.length;
697 String[] paths = new String[count];
698 for (int i = 0; i < count; i++) {
699 paths[i] = volumes[i].getPath();
700 }
701 return paths;
702 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700703
704 /** {@hide} */
Jeff Sharkey48877892015-03-18 11:27:19 -0700705 public @NonNull StorageVolume getPrimaryVolume() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700706 return getPrimaryVolume(getVolumeList());
707 }
708
709 /** {@hide} */
Jeff Sharkey48877892015-03-18 11:27:19 -0700710 public static @NonNull StorageVolume getPrimaryVolume(StorageVolume[] volumes) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700711 for (StorageVolume volume : volumes) {
712 if (volume.isPrimary()) {
713 return volume;
714 }
715 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700716 throw new IllegalStateException("Missing primary storage");
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700717 }
Jeff Sharkeybe722152013-02-15 16:56:38 -0800718
Jeff Sharkey48877892015-03-18 11:27:19 -0700719 /** {@hide} */
Jeff Sharkeybe722152013-02-15 16:56:38 -0800720 private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10;
721 private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500 * MB_IN_BYTES;
722 private static final long DEFAULT_FULL_THRESHOLD_BYTES = MB_IN_BYTES;
723
724 /**
Jeff Sharkey742e7902014-08-16 19:09:13 -0700725 * Return the number of available bytes until the given path is considered
726 * running low on storage.
727 *
728 * @hide
729 */
730 public long getStorageBytesUntilLow(File path) {
731 return path.getUsableSpace() - getStorageFullBytes(path);
732 }
733
734 /**
Jeff Sharkeybe722152013-02-15 16:56:38 -0800735 * Return the number of available bytes at which the given path is
736 * considered running low on storage.
737 *
738 * @hide
739 */
740 public long getStorageLowBytes(File path) {
741 final long lowPercent = Settings.Global.getInt(mResolver,
742 Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE);
743 final long lowBytes = (path.getTotalSpace() * lowPercent) / 100;
744
745 final long maxLowBytes = Settings.Global.getLong(mResolver,
746 Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES);
747
748 return Math.min(lowBytes, maxLowBytes);
749 }
750
751 /**
752 * Return the number of available bytes at which the given path is
753 * considered full.
754 *
755 * @hide
756 */
757 public long getStorageFullBytes(File path) {
758 return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
759 DEFAULT_FULL_THRESHOLD_BYTES);
760 }
Paul Lawrencee8fdc542014-05-28 07:14:17 -0700761
762 /// Consts to match the password types in cryptfs.h
763 /** @hide */
764 public static final int CRYPT_TYPE_PASSWORD = 0;
765 /** @hide */
766 public static final int CRYPT_TYPE_DEFAULT = 1;
767 /** @hide */
768 public static final int CRYPT_TYPE_PATTERN = 2;
769 /** @hide */
770 public static final int CRYPT_TYPE_PIN = 3;
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700771
772 // Constants for the data available via MountService.getField.
773 /** @hide */
774 public static final String SYSTEM_LOCALE_KEY = "SystemLocale";
775 /** @hide */
776 public static final String OWNER_INFO_KEY = "OwnerInfo";
777 /** @hide */
778 public static final String PATTERN_VISIBLE_KEY = "PatternVisible";
San Mehatb1043402010-02-05 08:26:50 -0800779}