blob: 0e977ff6f1b772c4fc0e69c68342cc3bf4f373cd [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";
72
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070073 /** {@hide} */
74 public static final int FLAG_ALL_METADATA = 1 << 0;
75
Jeff Sharkey48877892015-03-18 11:27:19 -070076 private final Context mContext;
Jeff Sharkeybe722152013-02-15 16:56:38 -080077 private final ContentResolver mResolver;
78
Jeff Sharkeybe722152013-02-15 16:56:38 -080079 private final IMountService mMountService;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070080 private final Looper mLooper;
81 private final AtomicInteger mNextNonce = new AtomicInteger(0);
San Mehatb1043402010-02-05 08:26:50 -080082
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070083 private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>();
San Mehatb1043402010-02-05 08:26:50 -080084
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070085 private static class StorageEventListenerDelegate extends IMountServiceListener.Stub implements
86 Handler.Callback {
87 private static final int MSG_STORAGE_STATE_CHANGED = 1;
88 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070089 private static final int MSG_VOLUME_METADATA_CHANGED = 3;
San Mehatb1043402010-02-05 08:26:50 -080090
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070091 final StorageEventListener mCallback;
92 final Handler mHandler;
Kenny Rootaf9d6672010-10-08 09:21:39 -070093
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070094 public StorageEventListenerDelegate(StorageEventListener callback, Looper looper) {
95 mCallback = callback;
96 mHandler = new Handler(looper, this);
San Mehatb1043402010-02-05 08:26:50 -080097 }
98
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070099 @Override
100 public boolean handleMessage(Message msg) {
101 final SomeArgs args = (SomeArgs) msg.obj;
102 switch (msg.what) {
103 case MSG_STORAGE_STATE_CHANGED:
104 mCallback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
105 (String) args.arg3);
106 args.recycle();
107 return true;
108 case MSG_VOLUME_STATE_CHANGED:
109 mCallback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
110 args.recycle();
111 return true;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700112 case MSG_VOLUME_METADATA_CHANGED:
113 mCallback.onVolumeMetadataChanged((VolumeInfo) args.arg1);
114 args.recycle();
115 return true;
San Mehatb1043402010-02-05 08:26:50 -0800116 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700117 args.recycle();
118 return false;
119 }
120
121 @Override
122 public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException {
123 // Ignored
124 }
125
126 @Override
127 public void onStorageStateChanged(String path, String oldState, String newState) {
128 final SomeArgs args = SomeArgs.obtain();
129 args.arg1 = path;
130 args.arg2 = oldState;
131 args.arg3 = newState;
132 mHandler.obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
133 }
134
135 @Override
136 public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
137 final SomeArgs args = SomeArgs.obtain();
138 args.arg1 = vol;
139 args.argi2 = oldState;
140 args.argi3 = newState;
141 mHandler.obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
San Mehatb1043402010-02-05 08:26:50 -0800142 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700143
144 @Override
145 public void onVolumeMetadataChanged(VolumeInfo vol) {
146 final SomeArgs args = SomeArgs.obtain();
147 args.arg1 = vol;
148 mHandler.obtainMessage(MSG_VOLUME_METADATA_CHANGED, args).sendToTarget();
149 }
San Mehatb1043402010-02-05 08:26:50 -0800150 }
151
152 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700153 * Binder listener for OBB action results.
154 */
Kenny Root05105f72010-09-22 17:29:43 -0700155 private final ObbActionListener mObbActionListener = new ObbActionListener();
156
157 private class ObbActionListener extends IObbActionListener.Stub {
Gilles Debunne37051cd2011-05-25 16:27:13 -0700158 @SuppressWarnings("hiding")
Kenny Rootaf9d6672010-10-08 09:21:39 -0700159 private SparseArray<ObbListenerDelegate> mListeners = new SparseArray<ObbListenerDelegate>();
Kenny Root05105f72010-09-22 17:29:43 -0700160
Kenny Roota02b8b02010-08-05 16:14:17 -0700161 @Override
Gilles Debunne37051cd2011-05-25 16:27:13 -0700162 public void onObbResult(String filename, int nonce, int status) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700163 final ObbListenerDelegate delegate;
Kenny Root05105f72010-09-22 17:29:43 -0700164 synchronized (mListeners) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700165 delegate = mListeners.get(nonce);
166 if (delegate != null) {
167 mListeners.remove(nonce);
Kenny Root05105f72010-09-22 17:29:43 -0700168 }
169 }
Kenny Rootaf9d6672010-10-08 09:21:39 -0700170
171 if (delegate != null) {
172 delegate.sendObbStateChanged(filename, status);
173 }
Kenny Root05105f72010-09-22 17:29:43 -0700174 }
175
Kenny Rootaf9d6672010-10-08 09:21:39 -0700176 public int addListener(OnObbStateChangeListener listener) {
177 final ObbListenerDelegate delegate = new ObbListenerDelegate(listener);
Kenny Root05105f72010-09-22 17:29:43 -0700178
179 synchronized (mListeners) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700180 mListeners.put(delegate.nonce, delegate);
Kenny Root05105f72010-09-22 17:29:43 -0700181 }
Kenny Rootaf9d6672010-10-08 09:21:39 -0700182
183 return delegate.nonce;
Kenny Root05105f72010-09-22 17:29:43 -0700184 }
185 }
186
Kenny Rootaf9d6672010-10-08 09:21:39 -0700187 private int getNextNonce() {
188 return mNextNonce.getAndIncrement();
189 }
190
Kenny Root05105f72010-09-22 17:29:43 -0700191 /**
192 * Private class containing sender and receiver code for StorageEvents.
193 */
194 private class ObbListenerDelegate {
195 private final WeakReference<OnObbStateChangeListener> mObbEventListenerRef;
196 private final Handler mHandler;
197
Kenny Rootaf9d6672010-10-08 09:21:39 -0700198 private final int nonce;
199
Kenny Root05105f72010-09-22 17:29:43 -0700200 ObbListenerDelegate(OnObbStateChangeListener listener) {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700201 nonce = getNextNonce();
Kenny Root05105f72010-09-22 17:29:43 -0700202 mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700203 mHandler = new Handler(mLooper) {
Kenny Root05105f72010-09-22 17:29:43 -0700204 @Override
205 public void handleMessage(Message msg) {
Gilles Debunne37051cd2011-05-25 16:27:13 -0700206 final OnObbStateChangeListener changeListener = getListener();
207 if (changeListener == null) {
Kenny Root05105f72010-09-22 17:29:43 -0700208 return;
209 }
210
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700211 changeListener.onObbStateChange((String) msg.obj, msg.arg1);
Kenny Root05105f72010-09-22 17:29:43 -0700212 }
213 };
214 }
215
216 OnObbStateChangeListener getListener() {
217 if (mObbEventListenerRef == null) {
218 return null;
219 }
220 return mObbEventListenerRef.get();
221 }
222
Kenny Rootaf9d6672010-10-08 09:21:39 -0700223 void sendObbStateChanged(String path, int state) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700224 mHandler.obtainMessage(0, state, 0, path).sendToTarget();
San Mehatb1043402010-02-05 08:26:50 -0800225 }
226 }
227
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700228 /** {@hide} */
229 public static StorageManager from(Context context) {
230 return (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
231 }
232
San Mehatb1043402010-02-05 08:26:50 -0800233 /**
234 * Constructs a StorageManager object through which an application can
235 * can communicate with the systems mount service.
236 *
Jeff Smitha45746e2012-07-19 14:19:24 -0500237 * @param tgtLooper The {@link android.os.Looper} which events will be received on.
San Mehatb1043402010-02-05 08:26:50 -0800238 *
239 * <p>Applications can get instance of this class by calling
240 * {@link android.content.Context#getSystemService(java.lang.String)} with an argument
241 * of {@link android.content.Context#STORAGE_SERVICE}.
242 *
243 * @hide
244 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700245 public StorageManager(Context context, Looper looper) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700246 mContext = context;
247 mResolver = context.getContentResolver();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700248 mLooper = looper;
San Mehatb1043402010-02-05 08:26:50 -0800249 mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
250 if (mMountService == null) {
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700251 throw new IllegalStateException("Failed to find running mount service");
San Mehatb1043402010-02-05 08:26:50 -0800252 }
San Mehatb1043402010-02-05 08:26:50 -0800253 }
254
San Mehatb1043402010-02-05 08:26:50 -0800255 /**
256 * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}.
257 *
258 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
259 *
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800260 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800261 */
262 public void registerListener(StorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700263 synchronized (mDelegates) {
264 final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(listener,
265 mLooper);
266 try {
267 mMountService.registerListener(delegate);
268 } catch (RemoteException e) {
269 throw e.rethrowAsRuntimeException();
Chuanxia Dong6614bb62012-05-29 12:28:24 +0800270 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700271 mDelegates.add(delegate);
San Mehatb1043402010-02-05 08:26:50 -0800272 }
273 }
274
275 /**
276 * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}.
277 *
278 * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object.
279 *
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800280 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800281 */
282 public void unregisterListener(StorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700283 synchronized (mDelegates) {
284 for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) {
285 final StorageEventListenerDelegate delegate = i.next();
286 if (delegate.mCallback == listener) {
287 try {
288 mMountService.unregisterListener(delegate);
289 } catch (RemoteException e) {
290 throw e.rethrowAsRuntimeException();
291 }
292 i.remove();
293 }
294 }
San Mehatb1043402010-02-05 08:26:50 -0800295 }
San Mehatb1043402010-02-05 08:26:50 -0800296 }
297
298 /**
299 * Enables USB Mass Storage (UMS) on the device.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800300 *
301 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800302 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700303 @Deprecated
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800304 public void enableUsbMassStorage() {
San Mehatb1043402010-02-05 08:26:50 -0800305 }
306
307 /**
308 * Disables USB Mass Storage (UMS) on the device.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800309 *
310 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800311 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700312 @Deprecated
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800313 public void disableUsbMassStorage() {
San Mehatb1043402010-02-05 08:26:50 -0800314 }
315
316 /**
317 * Query if a USB Mass Storage (UMS) host is connected.
318 * @return true if UMS host is connected.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800319 *
320 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800321 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700322 @Deprecated
San Mehatb1043402010-02-05 08:26:50 -0800323 public boolean isUsbMassStorageConnected() {
San Mehatb1043402010-02-05 08:26:50 -0800324 return false;
325 }
326
327 /**
328 * Query if a USB Mass Storage (UMS) is enabled on the device.
329 * @return true if UMS host is enabled.
Kenny Rootec7c9ff2011-01-17 09:11:21 -0800330 *
331 * @hide
San Mehatb1043402010-02-05 08:26:50 -0800332 */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700333 @Deprecated
San Mehatb1043402010-02-05 08:26:50 -0800334 public boolean isUsbMassStorageEnabled() {
San Mehatb1043402010-02-05 08:26:50 -0800335 return false;
336 }
Kenny Root02c87302010-07-01 08:10:18 -0700337
338 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700339 * Mount an Opaque Binary Blob (OBB) file. If a <code>key</code> is
340 * specified, it is supplied to the mounting process to be used in any
341 * encryption used in the OBB.
342 * <p>
Kenny Root05105f72010-09-22 17:29:43 -0700343 * The OBB will remain mounted for as long as the StorageManager reference
344 * is held by the application. As soon as this reference is lost, the OBBs
Kenny Rootaf9d6672010-10-08 09:21:39 -0700345 * in use will be unmounted. The {@link OnObbStateChangeListener} registered
346 * with this call will receive the success or failure of this operation.
Kenny Root05105f72010-09-22 17:29:43 -0700347 * <p>
Kenny Roota02b8b02010-08-05 16:14:17 -0700348 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
349 * file matches a package ID that is owned by the calling program's UID.
Kenny Root05105f72010-09-22 17:29:43 -0700350 * That is, shared UID applications can attempt to mount any other
Kenny Roota02b8b02010-08-05 16:14:17 -0700351 * application's OBB that shares its UID.
352 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700353 * @param rawPath the path to the OBB file
Kenny Root05105f72010-09-22 17:29:43 -0700354 * @param key secret used to encrypt the OBB; may be <code>null</code> if no
355 * encryption was used on the OBB.
Kenny Rootaf9d6672010-10-08 09:21:39 -0700356 * @param listener will receive the success or failure of the operation
Kenny Roota02b8b02010-08-05 16:14:17 -0700357 * @return whether the mount call was successfully queued or not
Kenny Root02c87302010-07-01 08:10:18 -0700358 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700359 public boolean mountObb(String rawPath, String key, OnObbStateChangeListener listener) {
360 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
361 Preconditions.checkNotNull(listener, "listener cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700362
Kenny Root02c87302010-07-01 08:10:18 -0700363 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700364 final String canonicalPath = new File(rawPath).getCanonicalPath();
Kenny Rootaf9d6672010-10-08 09:21:39 -0700365 final int nonce = mObbActionListener.addListener(listener);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700366 mMountService.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce);
Kenny Roota02b8b02010-08-05 16:14:17 -0700367 return true;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700368 } catch (IOException e) {
369 throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e);
Kenny Root02c87302010-07-01 08:10:18 -0700370 } catch (RemoteException e) {
371 Log.e(TAG, "Failed to mount OBB", e);
372 }
373
374 return false;
375 }
376
377 /**
Kenny Root05105f72010-09-22 17:29:43 -0700378 * Unmount an Opaque Binary Blob (OBB) file asynchronously. If the
379 * <code>force</code> flag is true, it will kill any application needed to
380 * unmount the given OBB (even the calling application).
381 * <p>
Kenny Rootaf9d6672010-10-08 09:21:39 -0700382 * The {@link OnObbStateChangeListener} registered with this call will
383 * receive the success or failure of this operation.
Kenny Roota02b8b02010-08-05 16:14:17 -0700384 * <p>
385 * <em>Note:</em> you can only mount OBB files for which the OBB tag on the
386 * file matches a package ID that is owned by the calling program's UID.
387 * That is, shared UID applications can obtain access to any other
388 * application's OBB that shares its UID.
Kenny Root02ca31f2010-08-12 07:36:02 -0700389 * <p>
Kenny Roota02b8b02010-08-05 16:14:17 -0700390 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700391 * @param rawPath path to the OBB file
Kenny Roota02b8b02010-08-05 16:14:17 -0700392 * @param force whether to kill any programs using this in order to unmount
393 * it
Kenny Rootaf9d6672010-10-08 09:21:39 -0700394 * @param listener will receive the success or failure of the operation
Kenny Roota02b8b02010-08-05 16:14:17 -0700395 * @return whether the unmount call was successfully queued or not
Kenny Root02c87302010-07-01 08:10:18 -0700396 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700397 public boolean unmountObb(String rawPath, boolean force, OnObbStateChangeListener listener) {
398 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
399 Preconditions.checkNotNull(listener, "listener cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700400
Kenny Root02c87302010-07-01 08:10:18 -0700401 try {
Kenny Rootaf9d6672010-10-08 09:21:39 -0700402 final int nonce = mObbActionListener.addListener(listener);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700403 mMountService.unmountObb(rawPath, force, mObbActionListener, nonce);
Kenny Roota02b8b02010-08-05 16:14:17 -0700404 return true;
Kenny Root02c87302010-07-01 08:10:18 -0700405 } catch (RemoteException e) {
406 Log.e(TAG, "Failed to mount OBB", e);
407 }
408
409 return false;
410 }
411
Kenny Roota02b8b02010-08-05 16:14:17 -0700412 /**
413 * Check whether an Opaque Binary Blob (OBB) is mounted or not.
414 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700415 * @param rawPath path to OBB image
Kenny Roota02b8b02010-08-05 16:14:17 -0700416 * @return true if OBB is mounted; false if not mounted or on error
417 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700418 public boolean isObbMounted(String rawPath) {
419 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700420
Kenny Root02c87302010-07-01 08:10:18 -0700421 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700422 return mMountService.isObbMounted(rawPath);
Kenny Root02c87302010-07-01 08:10:18 -0700423 } catch (RemoteException e) {
424 Log.e(TAG, "Failed to check if OBB is mounted", e);
425 }
426
427 return false;
428 }
429
430 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700431 * Check the mounted path of an Opaque Binary Blob (OBB) file. This will
432 * give you the path to where you can obtain access to the internals of the
433 * OBB.
434 *
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700435 * @param rawPath path to OBB image
Kenny Roota02b8b02010-08-05 16:14:17 -0700436 * @return absolute path to mounted OBB image data or <code>null</code> if
437 * not mounted or exception encountered trying to read status
Kenny Root02c87302010-07-01 08:10:18 -0700438 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700439 public String getMountedObbPath(String rawPath) {
440 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -0700441
Kenny Root02c87302010-07-01 08:10:18 -0700442 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700443 return mMountService.getMountedObbPath(rawPath);
Kenny Root02c87302010-07-01 08:10:18 -0700444 } catch (RemoteException e) {
445 Log.e(TAG, "Failed to find mounted path for OBB", e);
446 }
447
448 return null;
449 }
Mike Lockwoodd967f462011-03-24 08:12:30 -0700450
Jeff Sharkey48877892015-03-18 11:27:19 -0700451 /** {@hide} */
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700452 public @NonNull List<DiskInfo> getDisks() {
453 try {
454 return Arrays.asList(mMountService.getDisks());
455 } catch (RemoteException e) {
456 throw e.rethrowAsRuntimeException();
457 }
458 }
459
460 /** {@hide} */
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -0700461 public @Nullable DiskInfo findDiskById(String id) {
462 Preconditions.checkNotNull(id);
463 // TODO; go directly to service to make this faster
464 for (DiskInfo disk : getDisks()) {
465 if (Objects.equals(disk.id, id)) {
466 return disk;
467 }
468 }
469 return null;
470 }
471
472 /** {@hide} */
473 public @Nullable VolumeInfo findVolumeById(String id) {
474 Preconditions.checkNotNull(id);
475 // TODO; go directly to service to make this faster
476 for (VolumeInfo vol : getVolumes()) {
477 if (Objects.equals(vol.id, id)) {
478 return vol;
479 }
480 }
481 return null;
482 }
483
484 /** {@hide} */
485 public @Nullable VolumeInfo findVolumeByUuid(String fsUuid) {
486 Preconditions.checkNotNull(fsUuid);
487 // TODO; go directly to service to make this faster
488 for (VolumeInfo vol : getVolumes()) {
489 if (Objects.equals(vol.fsUuid, fsUuid)) {
490 return vol;
491 }
492 }
493 return null;
494 }
495
496 /** {@hide} */
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700497 public @NonNull List<VolumeInfo> getVolumes() {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700498 return getVolumes(0);
499 }
500
501 /** {@hide} */
502 public @NonNull List<VolumeInfo> getVolumes(int flags) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700503 try {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700504 return Arrays.asList(mMountService.getVolumes(flags));
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700505 } catch (RemoteException e) {
506 throw e.rethrowAsRuntimeException();
507 }
508 }
509
510 /** {@hide} */
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700511 public @Nullable String getBestVolumeDescription(VolumeInfo vol) {
512 String descrip = vol.getDescription();
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700513
Jeff Sharkey56bd3122015-04-14 10:30:34 -0700514 if (vol.diskId != null) {
515 final DiskInfo disk = findDiskById(vol.diskId);
516 if (disk != null && TextUtils.isEmpty(descrip)) {
517 descrip = disk.getDescription();
518 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700519 }
520
521 return descrip;
522 }
523
524 /** {@hide} */
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700525 public void mount(String volId) {
526 try {
527 mMountService.mount(volId);
528 } catch (RemoteException e) {
529 throw e.rethrowAsRuntimeException();
530 }
531 }
532
533 /** {@hide} */
534 public void unmount(String volId) {
535 try {
536 mMountService.unmount(volId);
537 } catch (RemoteException e) {
538 throw e.rethrowAsRuntimeException();
539 }
540 }
541
542 /** {@hide} */
543 public void format(String volId) {
544 try {
545 mMountService.format(volId);
546 } catch (RemoteException e) {
547 throw e.rethrowAsRuntimeException();
548 }
549 }
550
551 /** {@hide} */
552 public void partitionPublic(String diskId) {
553 try {
554 mMountService.partitionPublic(diskId);
555 } catch (RemoteException e) {
556 throw e.rethrowAsRuntimeException();
557 }
558 }
559
560 /** {@hide} */
561 public void partitionPrivate(String diskId) {
562 try {
563 mMountService.partitionPrivate(diskId);
564 } catch (RemoteException e) {
565 throw e.rethrowAsRuntimeException();
566 }
567 }
568
569 /** {@hide} */
570 public void partitionMixed(String diskId, int ratio) {
571 try {
572 mMountService.partitionMixed(diskId, ratio);
573 } catch (RemoteException e) {
574 throw e.rethrowAsRuntimeException();
575 }
576 }
577
578 /** {@hide} */
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700579 public void setVolumeNickname(String volId, String nickname) {
580 try {
581 mMountService.setVolumeNickname(volId, nickname);
582 } catch (RemoteException e) {
583 throw e.rethrowAsRuntimeException();
584 }
585 }
586
587 /** {@hide} */
588 public void setVolumeInited(String volId, boolean inited) {
589 try {
590 mMountService.setVolumeUserFlags(volId, inited ? VolumeInfo.USER_FLAG_INITED : 0,
591 VolumeInfo.USER_FLAG_INITED);
592 } catch (RemoteException e) {
593 throw e.rethrowAsRuntimeException();
594 }
595 }
596
597 /** {@hide} */
598 public void setVolumeSnoozed(String volId, boolean snoozed) {
599 try {
600 mMountService.setVolumeUserFlags(volId, snoozed ? VolumeInfo.USER_FLAG_SNOOZED : 0,
601 VolumeInfo.USER_FLAG_SNOOZED);
602 } catch (RemoteException e) {
603 throw e.rethrowAsRuntimeException();
604 }
605 }
606
607 /** {@hide} */
Jeff Sharkey48877892015-03-18 11:27:19 -0700608 public @Nullable StorageVolume getStorageVolume(File file) {
609 return getStorageVolume(getVolumeList(), file);
610 }
611
612 /** {@hide} */
613 public static @Nullable StorageVolume getStorageVolume(File file, int userId) {
614 return getStorageVolume(getVolumeList(userId), file);
615 }
616
617 /** {@hide} */
618 private static @Nullable StorageVolume getStorageVolume(StorageVolume[] volumes, File file) {
619 File canonicalFile = null;
620 try {
621 canonicalFile = file.getCanonicalFile();
622 } catch (IOException ignored) {
623 canonicalFile = null;
624 }
625 for (StorageVolume volume : volumes) {
626 if (volume.getPathFile().equals(file)) {
627 return volume;
628 }
629 if (FileUtils.contains(volume.getPathFile(), canonicalFile)) {
630 return volume;
631 }
632 }
633 return null;
634 }
635
Mike Lockwoodd967f462011-03-24 08:12:30 -0700636 /**
637 * Gets the state of a volume via its mountpoint.
638 * @hide
639 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700640 @Deprecated
641 public @NonNull String getVolumeState(String mountPoint) {
642 final StorageVolume vol = getStorageVolume(new File(mountPoint));
643 if (vol != null) {
644 return vol.getState();
645 } else {
646 return Environment.MEDIA_UNKNOWN;
Mike Lockwoodd967f462011-03-24 08:12:30 -0700647 }
648 }
649
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700650 /** {@hide} */
Jeff Sharkey48877892015-03-18 11:27:19 -0700651 public @NonNull StorageVolume[] getVolumeList() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700652 return getVolumeList(mContext.getUserId());
Jeff Sharkey48877892015-03-18 11:27:19 -0700653 }
654
655 /** {@hide} */
656 public static @NonNull StorageVolume[] getVolumeList(int userId) {
657 final IMountService mountService = IMountService.Stub.asInterface(
658 ServiceManager.getService("mount"));
659 try {
660 return mountService.getVolumeList(userId);
661 } catch (RemoteException e) {
662 throw e.rethrowAsRuntimeException();
Mike Lockwoodd967f462011-03-24 08:12:30 -0700663 }
664 }
Mike Lockwood2f6a3882011-05-09 19:08:06 -0700665
666 /**
667 * Returns list of paths for all mountable volumes.
668 * @hide
669 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700670 @Deprecated
671 public @NonNull String[] getVolumePaths() {
Mike Lockwood2f6a3882011-05-09 19:08:06 -0700672 StorageVolume[] volumes = getVolumeList();
Mike Lockwood2f6a3882011-05-09 19:08:06 -0700673 int count = volumes.length;
674 String[] paths = new String[count];
675 for (int i = 0; i < count; i++) {
676 paths[i] = volumes[i].getPath();
677 }
678 return paths;
679 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700680
681 /** {@hide} */
Jeff Sharkey48877892015-03-18 11:27:19 -0700682 public @NonNull StorageVolume getPrimaryVolume() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700683 return getPrimaryVolume(getVolumeList());
684 }
685
686 /** {@hide} */
Jeff Sharkey48877892015-03-18 11:27:19 -0700687 public static @NonNull StorageVolume getPrimaryVolume(StorageVolume[] volumes) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700688 for (StorageVolume volume : volumes) {
689 if (volume.isPrimary()) {
690 return volume;
691 }
692 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700693 throw new IllegalStateException("Missing primary storage");
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700694 }
Jeff Sharkeybe722152013-02-15 16:56:38 -0800695
Jeff Sharkey48877892015-03-18 11:27:19 -0700696 /** {@hide} */
Jeff Sharkeybe722152013-02-15 16:56:38 -0800697 private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10;
698 private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500 * MB_IN_BYTES;
699 private static final long DEFAULT_FULL_THRESHOLD_BYTES = MB_IN_BYTES;
700
701 /**
Jeff Sharkey742e7902014-08-16 19:09:13 -0700702 * Return the number of available bytes until the given path is considered
703 * running low on storage.
704 *
705 * @hide
706 */
707 public long getStorageBytesUntilLow(File path) {
708 return path.getUsableSpace() - getStorageFullBytes(path);
709 }
710
711 /**
Jeff Sharkeybe722152013-02-15 16:56:38 -0800712 * Return the number of available bytes at which the given path is
713 * considered running low on storage.
714 *
715 * @hide
716 */
717 public long getStorageLowBytes(File path) {
718 final long lowPercent = Settings.Global.getInt(mResolver,
719 Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE);
720 final long lowBytes = (path.getTotalSpace() * lowPercent) / 100;
721
722 final long maxLowBytes = Settings.Global.getLong(mResolver,
723 Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES);
724
725 return Math.min(lowBytes, maxLowBytes);
726 }
727
728 /**
729 * Return the number of available bytes at which the given path is
730 * considered full.
731 *
732 * @hide
733 */
734 public long getStorageFullBytes(File path) {
735 return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
736 DEFAULT_FULL_THRESHOLD_BYTES);
737 }
Paul Lawrencee8fdc542014-05-28 07:14:17 -0700738
739 /// Consts to match the password types in cryptfs.h
740 /** @hide */
741 public static final int CRYPT_TYPE_PASSWORD = 0;
742 /** @hide */
743 public static final int CRYPT_TYPE_DEFAULT = 1;
744 /** @hide */
745 public static final int CRYPT_TYPE_PATTERN = 2;
746 /** @hide */
747 public static final int CRYPT_TYPE_PIN = 3;
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700748
749 // Constants for the data available via MountService.getField.
750 /** @hide */
751 public static final String SYSTEM_LOCALE_KEY = "SystemLocale";
752 /** @hide */
753 public static final String OWNER_INFO_KEY = "OwnerInfo";
754 /** @hide */
755 public static final String PATTERN_VISIBLE_KEY = "PatternVisible";
San Mehatb1043402010-02-05 08:26:50 -0800756}