1b104340496e3a531e26c8f428c808eca0e039f50San Mehat/* 2b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Copyright (C) 2008 The Android Open Source Project 3b104340496e3a531e26c8f428c808eca0e039f50San Mehat * 4b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Licensed under the Apache License, Version 2.0 (the "License"); 5b104340496e3a531e26c8f428c808eca0e039f50San Mehat * you may not use this file except in compliance with the License. 6b104340496e3a531e26c8f428c808eca0e039f50San Mehat * You may obtain a copy of the License at 7b104340496e3a531e26c8f428c808eca0e039f50San Mehat * 8b104340496e3a531e26c8f428c808eca0e039f50San Mehat * http://www.apache.org/licenses/LICENSE-2.0 9b104340496e3a531e26c8f428c808eca0e039f50San Mehat * 10b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Unless required by applicable law or agreed to in writing, software 11b104340496e3a531e26c8f428c808eca0e039f50San Mehat * distributed under the License is distributed on an "AS IS" BASIS, 12b104340496e3a531e26c8f428c808eca0e039f50San Mehat * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b104340496e3a531e26c8f428c808eca0e039f50San Mehat * See the License for the specific language governing permissions and 14b104340496e3a531e26c8f428c808eca0e039f50San Mehat * limitations under the License. 15b104340496e3a531e26c8f428c808eca0e039f50San Mehat */ 16b104340496e3a531e26c8f428c808eca0e039f50San Mehat 17b104340496e3a531e26c8f428c808eca0e039f50San Mehatpackage android.os.storage; 18b104340496e3a531e26c8f428c808eca0e039f50San Mehat 19be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkeyimport static android.net.TrafficStats.MB_IN_BYTES; 20be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey 21be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkeyimport android.content.ContentResolver; 22b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport android.content.Context; 23cba928cef7d614d375253246f014c4a52bb8b913Mike Lockwoodimport android.os.Environment; 24b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.os.Handler; 25a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.Looper; 26b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.os.Message; 272f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.os.Parcelable; 28a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.RemoteException; 29b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.os.ServiceManager; 30be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkeyimport android.provider.Settings; 31b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.util.Log; 32af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Rootimport android.util.SparseArray; 33b104340496e3a531e26c8f428c808eca0e039f50San Mehat 344fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkeyimport com.android.internal.util.Preconditions; 354fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 364fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkeyimport java.io.File; 374fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkeyimport java.io.IOException; 3805105f7abe02b2dff91d6260b3628c8b97816babKenny Rootimport java.lang.ref.WeakReference; 39b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport java.util.ArrayList; 4005105f7abe02b2dff91d6260b3628c8b97816babKenny Rootimport java.util.List; 41af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Rootimport java.util.concurrent.atomic.AtomicInteger; 42b104340496e3a531e26c8f428c808eca0e039f50San Mehat 43b104340496e3a531e26c8f428c808eca0e039f50San Mehat/** 4405105f7abe02b2dff91d6260b3628c8b97816babKenny Root * StorageManager is the interface to the systems storage service. The storage 4505105f7abe02b2dff91d6260b3628c8b97816babKenny Root * manager handles storage-related items such as Opaque Binary Blobs (OBBs). 4605105f7abe02b2dff91d6260b3628c8b97816babKenny Root * <p> 4705105f7abe02b2dff91d6260b3628c8b97816babKenny Root * OBBs contain a filesystem that maybe be encrypted on disk and mounted 4805105f7abe02b2dff91d6260b3628c8b97816babKenny Root * on-demand from an application. OBBs are a good way of providing large amounts 4905105f7abe02b2dff91d6260b3628c8b97816babKenny Root * of binary assets without packaging them into APKs as they may be multiple 5005105f7abe02b2dff91d6260b3628c8b97816babKenny Root * gigabytes in size. However, due to their size, they're most likely stored in 5105105f7abe02b2dff91d6260b3628c8b97816babKenny Root * a shared storage pool accessible from all programs. The system does not 5205105f7abe02b2dff91d6260b3628c8b97816babKenny Root * guarantee the security of the OBB file itself: if any program modifies the 5305105f7abe02b2dff91d6260b3628c8b97816babKenny Root * OBB, there is no guarantee that a read from that OBB will produce the 5405105f7abe02b2dff91d6260b3628c8b97816babKenny Root * expected output. 5505105f7abe02b2dff91d6260b3628c8b97816babKenny Root * <p> 56b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Get an instance of this class by calling 5705105f7abe02b2dff91d6260b3628c8b97816babKenny Root * {@link android.content.Context#getSystemService(java.lang.String)} with an 5805105f7abe02b2dff91d6260b3628c8b97816babKenny Root * argument of {@link android.content.Context#STORAGE_SERVICE}. 59b104340496e3a531e26c8f428c808eca0e039f50San Mehat */ 60be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkeypublic class StorageManager { 61b104340496e3a531e26c8f428c808eca0e039f50San Mehat private static final String TAG = "StorageManager"; 62b104340496e3a531e26c8f428c808eca0e039f50San Mehat 63be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey private final ContentResolver mResolver; 64be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey 65b104340496e3a531e26c8f428c808eca0e039f50San Mehat /* 66b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Our internal MountService binder reference 67b104340496e3a531e26c8f428c808eca0e039f50San Mehat */ 68be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey private final IMountService mMountService; 69b104340496e3a531e26c8f428c808eca0e039f50San Mehat 70b104340496e3a531e26c8f428c808eca0e039f50San Mehat /* 71b104340496e3a531e26c8f428c808eca0e039f50San Mehat * The looper target for callbacks 72b104340496e3a531e26c8f428c808eca0e039f50San Mehat */ 73be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey private final Looper mTgtLooper; 74b104340496e3a531e26c8f428c808eca0e039f50San Mehat 75b104340496e3a531e26c8f428c808eca0e039f50San Mehat /* 76b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Target listener for binder callbacks 77b104340496e3a531e26c8f428c808eca0e039f50San Mehat */ 78b104340496e3a531e26c8f428c808eca0e039f50San Mehat private MountServiceBinderListener mBinderListener; 79b104340496e3a531e26c8f428c808eca0e039f50San Mehat 80b104340496e3a531e26c8f428c808eca0e039f50San Mehat /* 81b104340496e3a531e26c8f428c808eca0e039f50San Mehat * List of our listeners 82b104340496e3a531e26c8f428c808eca0e039f50San Mehat */ 83af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private List<ListenerDelegate> mListeners = new ArrayList<ListenerDelegate>(); 84af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 85af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root /* 86af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * Next available nonce 87af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root */ 88af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final private AtomicInteger mNextNonce = new AtomicInteger(0); 89b104340496e3a531e26c8f428c808eca0e039f50San Mehat 90b104340496e3a531e26c8f428c808eca0e039f50San Mehat private class MountServiceBinderListener extends IMountServiceListener.Stub { 91b104340496e3a531e26c8f428c808eca0e039f50San Mehat public void onUsbMassStorageConnectionChanged(boolean available) { 92b104340496e3a531e26c8f428c808eca0e039f50San Mehat final int size = mListeners.size(); 93b104340496e3a531e26c8f428c808eca0e039f50San Mehat for (int i = 0; i < size; i++) { 94b104340496e3a531e26c8f428c808eca0e039f50San Mehat mListeners.get(i).sendShareAvailabilityChanged(available); 95b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 96b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 97b104340496e3a531e26c8f428c808eca0e039f50San Mehat 98b104340496e3a531e26c8f428c808eca0e039f50San Mehat public void onStorageStateChanged(String path, String oldState, String newState) { 99b104340496e3a531e26c8f428c808eca0e039f50San Mehat final int size = mListeners.size(); 100b104340496e3a531e26c8f428c808eca0e039f50San Mehat for (int i = 0; i < size; i++) { 101b104340496e3a531e26c8f428c808eca0e039f50San Mehat mListeners.get(i).sendStorageStateChanged(path, oldState, newState); 102b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 103b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 104b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 105b104340496e3a531e26c8f428c808eca0e039f50San Mehat 106b104340496e3a531e26c8f428c808eca0e039f50San Mehat /** 107a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * Binder listener for OBB action results. 108a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root */ 10905105f7abe02b2dff91d6260b3628c8b97816babKenny Root private final ObbActionListener mObbActionListener = new ObbActionListener(); 11005105f7abe02b2dff91d6260b3628c8b97816babKenny Root 11105105f7abe02b2dff91d6260b3628c8b97816babKenny Root private class ObbActionListener extends IObbActionListener.Stub { 11237051cdd8624c4821bb68169be427061c48ad837Gilles Debunne @SuppressWarnings("hiding") 113af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private SparseArray<ObbListenerDelegate> mListeners = new SparseArray<ObbListenerDelegate>(); 11405105f7abe02b2dff91d6260b3628c8b97816babKenny Root 115a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 11637051cdd8624c4821bb68169be427061c48ad837Gilles Debunne public void onObbResult(String filename, int nonce, int status) { 117af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbListenerDelegate delegate; 11805105f7abe02b2dff91d6260b3628c8b97816babKenny Root synchronized (mListeners) { 119af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root delegate = mListeners.get(nonce); 120af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (delegate != null) { 121af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mListeners.remove(nonce); 12205105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 12305105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 12405105f7abe02b2dff91d6260b3628c8b97816babKenny Root 125af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (delegate != null) { 126af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root delegate.sendObbStateChanged(filename, status); 12705105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 128af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 12905105f7abe02b2dff91d6260b3628c8b97816babKenny Root 130af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root public int addListener(OnObbStateChangeListener listener) { 131af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbListenerDelegate delegate = new ObbListenerDelegate(listener); 13205105f7abe02b2dff91d6260b3628c8b97816babKenny Root 133af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mListeners) { 134af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mListeners.put(delegate.nonce, delegate); 13505105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 136af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 137af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return delegate.nonce; 13805105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 13905105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 14005105f7abe02b2dff91d6260b3628c8b97816babKenny Root 141af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private int getNextNonce() { 142af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return mNextNonce.getAndIncrement(); 143af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 144af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 14505105f7abe02b2dff91d6260b3628c8b97816babKenny Root /** 14605105f7abe02b2dff91d6260b3628c8b97816babKenny Root * Private class containing sender and receiver code for StorageEvents. 14705105f7abe02b2dff91d6260b3628c8b97816babKenny Root */ 14805105f7abe02b2dff91d6260b3628c8b97816babKenny Root private class ObbListenerDelegate { 14905105f7abe02b2dff91d6260b3628c8b97816babKenny Root private final WeakReference<OnObbStateChangeListener> mObbEventListenerRef; 15005105f7abe02b2dff91d6260b3628c8b97816babKenny Root private final Handler mHandler; 15105105f7abe02b2dff91d6260b3628c8b97816babKenny Root 152af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private final int nonce; 153af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 15405105f7abe02b2dff91d6260b3628c8b97816babKenny Root ObbListenerDelegate(OnObbStateChangeListener listener) { 155af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root nonce = getNextNonce(); 15605105f7abe02b2dff91d6260b3628c8b97816babKenny Root mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener); 15705105f7abe02b2dff91d6260b3628c8b97816babKenny Root mHandler = new Handler(mTgtLooper) { 15805105f7abe02b2dff91d6260b3628c8b97816babKenny Root @Override 15905105f7abe02b2dff91d6260b3628c8b97816babKenny Root public void handleMessage(Message msg) { 16037051cdd8624c4821bb68169be427061c48ad837Gilles Debunne final OnObbStateChangeListener changeListener = getListener(); 16137051cdd8624c4821bb68169be427061c48ad837Gilles Debunne if (changeListener == null) { 16205105f7abe02b2dff91d6260b3628c8b97816babKenny Root return; 16305105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 16405105f7abe02b2dff91d6260b3628c8b97816babKenny Root 16505105f7abe02b2dff91d6260b3628c8b97816babKenny Root StorageEvent e = (StorageEvent) msg.obj; 16605105f7abe02b2dff91d6260b3628c8b97816babKenny Root 16705105f7abe02b2dff91d6260b3628c8b97816babKenny Root if (msg.what == StorageEvent.EVENT_OBB_STATE_CHANGED) { 16805105f7abe02b2dff91d6260b3628c8b97816babKenny Root ObbStateChangedStorageEvent ev = (ObbStateChangedStorageEvent) e; 16937051cdd8624c4821bb68169be427061c48ad837Gilles Debunne changeListener.onObbStateChange(ev.path, ev.state); 17005105f7abe02b2dff91d6260b3628c8b97816babKenny Root } else { 17105105f7abe02b2dff91d6260b3628c8b97816babKenny Root Log.e(TAG, "Unsupported event " + msg.what); 17205105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 17305105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 17405105f7abe02b2dff91d6260b3628c8b97816babKenny Root }; 17505105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 17605105f7abe02b2dff91d6260b3628c8b97816babKenny Root 17705105f7abe02b2dff91d6260b3628c8b97816babKenny Root OnObbStateChangeListener getListener() { 17805105f7abe02b2dff91d6260b3628c8b97816babKenny Root if (mObbEventListenerRef == null) { 17905105f7abe02b2dff91d6260b3628c8b97816babKenny Root return null; 18005105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 18105105f7abe02b2dff91d6260b3628c8b97816babKenny Root return mObbEventListenerRef.get(); 18205105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 18305105f7abe02b2dff91d6260b3628c8b97816babKenny Root 184af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root void sendObbStateChanged(String path, int state) { 18505105f7abe02b2dff91d6260b3628c8b97816babKenny Root ObbStateChangedStorageEvent e = new ObbStateChangedStorageEvent(path, state); 18605105f7abe02b2dff91d6260b3628c8b97816babKenny Root mHandler.sendMessage(e.getMessage()); 18705105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 18805105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 18905105f7abe02b2dff91d6260b3628c8b97816babKenny Root 19005105f7abe02b2dff91d6260b3628c8b97816babKenny Root /** 19105105f7abe02b2dff91d6260b3628c8b97816babKenny Root * Message sent during an OBB status change event. 19205105f7abe02b2dff91d6260b3628c8b97816babKenny Root */ 19305105f7abe02b2dff91d6260b3628c8b97816babKenny Root private class ObbStateChangedStorageEvent extends StorageEvent { 19405105f7abe02b2dff91d6260b3628c8b97816babKenny Root public final String path; 19505105f7abe02b2dff91d6260b3628c8b97816babKenny Root 196af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root public final int state; 197af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 198af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root public ObbStateChangedStorageEvent(String path, int state) { 19905105f7abe02b2dff91d6260b3628c8b97816babKenny Root super(EVENT_OBB_STATE_CHANGED); 20005105f7abe02b2dff91d6260b3628c8b97816babKenny Root this.path = path; 20105105f7abe02b2dff91d6260b3628c8b97816babKenny Root this.state = state; 202a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 203a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 204a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 205a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root /** 206b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Private base class for messages sent between the callback thread 207b104340496e3a531e26c8f428c808eca0e039f50San Mehat * and the target looper handler. 208b104340496e3a531e26c8f428c808eca0e039f50San Mehat */ 209b104340496e3a531e26c8f428c808eca0e039f50San Mehat private class StorageEvent { 21005105f7abe02b2dff91d6260b3628c8b97816babKenny Root static final int EVENT_UMS_CONNECTION_CHANGED = 1; 21105105f7abe02b2dff91d6260b3628c8b97816babKenny Root static final int EVENT_STORAGE_STATE_CHANGED = 2; 21205105f7abe02b2dff91d6260b3628c8b97816babKenny Root static final int EVENT_OBB_STATE_CHANGED = 3; 213b104340496e3a531e26c8f428c808eca0e039f50San Mehat 214b104340496e3a531e26c8f428c808eca0e039f50San Mehat private Message mMessage; 215b104340496e3a531e26c8f428c808eca0e039f50San Mehat 216b104340496e3a531e26c8f428c808eca0e039f50San Mehat public StorageEvent(int what) { 217b104340496e3a531e26c8f428c808eca0e039f50San Mehat mMessage = Message.obtain(); 218b104340496e3a531e26c8f428c808eca0e039f50San Mehat mMessage.what = what; 219b104340496e3a531e26c8f428c808eca0e039f50San Mehat mMessage.obj = this; 220b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 221b104340496e3a531e26c8f428c808eca0e039f50San Mehat 222b104340496e3a531e26c8f428c808eca0e039f50San Mehat public Message getMessage() { 223b104340496e3a531e26c8f428c808eca0e039f50San Mehat return mMessage; 224b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 225b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 226b104340496e3a531e26c8f428c808eca0e039f50San Mehat 227b104340496e3a531e26c8f428c808eca0e039f50San Mehat /** 228b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Message sent on a USB mass storage connection change. 229b104340496e3a531e26c8f428c808eca0e039f50San Mehat */ 230b104340496e3a531e26c8f428c808eca0e039f50San Mehat private class UmsConnectionChangedStorageEvent extends StorageEvent { 231b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean available; 232b104340496e3a531e26c8f428c808eca0e039f50San Mehat 233b104340496e3a531e26c8f428c808eca0e039f50San Mehat public UmsConnectionChangedStorageEvent(boolean a) { 234b104340496e3a531e26c8f428c808eca0e039f50San Mehat super(EVENT_UMS_CONNECTION_CHANGED); 235b104340496e3a531e26c8f428c808eca0e039f50San Mehat available = a; 236b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 237b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 238b104340496e3a531e26c8f428c808eca0e039f50San Mehat 239b104340496e3a531e26c8f428c808eca0e039f50San Mehat /** 240b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Message sent on volume state change. 241b104340496e3a531e26c8f428c808eca0e039f50San Mehat */ 242b104340496e3a531e26c8f428c808eca0e039f50San Mehat private class StorageStateChangedStorageEvent extends StorageEvent { 243b104340496e3a531e26c8f428c808eca0e039f50San Mehat public String path; 244b104340496e3a531e26c8f428c808eca0e039f50San Mehat public String oldState; 245b104340496e3a531e26c8f428c808eca0e039f50San Mehat public String newState; 246b104340496e3a531e26c8f428c808eca0e039f50San Mehat 247b104340496e3a531e26c8f428c808eca0e039f50San Mehat public StorageStateChangedStorageEvent(String p, String oldS, String newS) { 248b104340496e3a531e26c8f428c808eca0e039f50San Mehat super(EVENT_STORAGE_STATE_CHANGED); 249b104340496e3a531e26c8f428c808eca0e039f50San Mehat path = p; 250b104340496e3a531e26c8f428c808eca0e039f50San Mehat oldState = oldS; 251b104340496e3a531e26c8f428c808eca0e039f50San Mehat newState = newS; 252b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 253b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 254b104340496e3a531e26c8f428c808eca0e039f50San Mehat 255b104340496e3a531e26c8f428c808eca0e039f50San Mehat /** 256b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Private class containing sender and receiver code for StorageEvents. 257b104340496e3a531e26c8f428c808eca0e039f50San Mehat */ 258b104340496e3a531e26c8f428c808eca0e039f50San Mehat private class ListenerDelegate { 259b104340496e3a531e26c8f428c808eca0e039f50San Mehat final StorageEventListener mStorageEventListener; 260b104340496e3a531e26c8f428c808eca0e039f50San Mehat private final Handler mHandler; 261b104340496e3a531e26c8f428c808eca0e039f50San Mehat 262b104340496e3a531e26c8f428c808eca0e039f50San Mehat ListenerDelegate(StorageEventListener listener) { 263b104340496e3a531e26c8f428c808eca0e039f50San Mehat mStorageEventListener = listener; 264b104340496e3a531e26c8f428c808eca0e039f50San Mehat mHandler = new Handler(mTgtLooper) { 265b104340496e3a531e26c8f428c808eca0e039f50San Mehat @Override 266b104340496e3a531e26c8f428c808eca0e039f50San Mehat public void handleMessage(Message msg) { 267b104340496e3a531e26c8f428c808eca0e039f50San Mehat StorageEvent e = (StorageEvent) msg.obj; 268b104340496e3a531e26c8f428c808eca0e039f50San Mehat 269b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (msg.what == StorageEvent.EVENT_UMS_CONNECTION_CHANGED) { 270b104340496e3a531e26c8f428c808eca0e039f50San Mehat UmsConnectionChangedStorageEvent ev = (UmsConnectionChangedStorageEvent) e; 271b104340496e3a531e26c8f428c808eca0e039f50San Mehat mStorageEventListener.onUsbMassStorageConnectionChanged(ev.available); 272b104340496e3a531e26c8f428c808eca0e039f50San Mehat } else if (msg.what == StorageEvent.EVENT_STORAGE_STATE_CHANGED) { 273b104340496e3a531e26c8f428c808eca0e039f50San Mehat StorageStateChangedStorageEvent ev = (StorageStateChangedStorageEvent) e; 274b104340496e3a531e26c8f428c808eca0e039f50San Mehat mStorageEventListener.onStorageStateChanged(ev.path, ev.oldState, ev.newState); 275b104340496e3a531e26c8f428c808eca0e039f50San Mehat } else { 276b104340496e3a531e26c8f428c808eca0e039f50San Mehat Log.e(TAG, "Unsupported event " + msg.what); 277b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 278b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 279b104340496e3a531e26c8f428c808eca0e039f50San Mehat }; 280b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 281b104340496e3a531e26c8f428c808eca0e039f50San Mehat 282b104340496e3a531e26c8f428c808eca0e039f50San Mehat StorageEventListener getListener() { 283b104340496e3a531e26c8f428c808eca0e039f50San Mehat return mStorageEventListener; 284b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 285b104340496e3a531e26c8f428c808eca0e039f50San Mehat 286b104340496e3a531e26c8f428c808eca0e039f50San Mehat void sendShareAvailabilityChanged(boolean available) { 287b104340496e3a531e26c8f428c808eca0e039f50San Mehat UmsConnectionChangedStorageEvent e = new UmsConnectionChangedStorageEvent(available); 288b104340496e3a531e26c8f428c808eca0e039f50San Mehat mHandler.sendMessage(e.getMessage()); 289b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 290b104340496e3a531e26c8f428c808eca0e039f50San Mehat 291b104340496e3a531e26c8f428c808eca0e039f50San Mehat void sendStorageStateChanged(String path, String oldState, String newState) { 292b104340496e3a531e26c8f428c808eca0e039f50San Mehat StorageStateChangedStorageEvent e = new StorageStateChangedStorageEvent(path, oldState, newState); 293b104340496e3a531e26c8f428c808eca0e039f50San Mehat mHandler.sendMessage(e.getMessage()); 294b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 295b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 296b104340496e3a531e26c8f428c808eca0e039f50San Mehat 297b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey /** {@hide} */ 298b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey public static StorageManager from(Context context) { 299b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey return (StorageManager) context.getSystemService(Context.STORAGE_SERVICE); 300b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 301b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 302b104340496e3a531e26c8f428c808eca0e039f50San Mehat /** 303b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Constructs a StorageManager object through which an application can 304b104340496e3a531e26c8f428c808eca0e039f50San Mehat * can communicate with the systems mount service. 305b104340496e3a531e26c8f428c808eca0e039f50San Mehat * 306a45746efadd11bb7dfab026fb3c81a25fae74ca4Jeff Smith * @param tgtLooper The {@link android.os.Looper} which events will be received on. 307b104340496e3a531e26c8f428c808eca0e039f50San Mehat * 308b104340496e3a531e26c8f428c808eca0e039f50San Mehat * <p>Applications can get instance of this class by calling 309b104340496e3a531e26c8f428c808eca0e039f50San Mehat * {@link android.content.Context#getSystemService(java.lang.String)} with an argument 310b104340496e3a531e26c8f428c808eca0e039f50San Mehat * of {@link android.content.Context#STORAGE_SERVICE}. 311b104340496e3a531e26c8f428c808eca0e039f50San Mehat * 312b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @hide 313b104340496e3a531e26c8f428c808eca0e039f50San Mehat */ 314be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey public StorageManager(ContentResolver resolver, Looper tgtLooper) throws RemoteException { 315be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey mResolver = resolver; 316be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey mTgtLooper = tgtLooper; 317b104340496e3a531e26c8f428c808eca0e039f50San Mehat mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount")); 318b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (mMountService == null) { 319b104340496e3a531e26c8f428c808eca0e039f50San Mehat Log.e(TAG, "Unable to connect to mount service! - is it running yet?"); 320b104340496e3a531e26c8f428c808eca0e039f50San Mehat return; 321b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 322b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 323b104340496e3a531e26c8f428c808eca0e039f50San Mehat 324b104340496e3a531e26c8f428c808eca0e039f50San Mehat /** 325b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Registers a {@link android.os.storage.StorageEventListener StorageEventListener}. 326b104340496e3a531e26c8f428c808eca0e039f50San Mehat * 327b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object. 328b104340496e3a531e26c8f428c808eca0e039f50San Mehat * 329ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root * @hide 330b104340496e3a531e26c8f428c808eca0e039f50San Mehat */ 331b104340496e3a531e26c8f428c808eca0e039f50San Mehat public void registerListener(StorageEventListener listener) { 332b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (listener == null) { 333b104340496e3a531e26c8f428c808eca0e039f50San Mehat return; 334b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 335b104340496e3a531e26c8f428c808eca0e039f50San Mehat 336b104340496e3a531e26c8f428c808eca0e039f50San Mehat synchronized (mListeners) { 3376614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong if (mBinderListener == null ) { 3386614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong try { 3396614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong mBinderListener = new MountServiceBinderListener(); 3406614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong mMountService.registerListener(mBinderListener); 3416614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong } catch (RemoteException rex) { 3426614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong Log.e(TAG, "Register mBinderListener failed"); 3436614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong return; 3446614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong } 3456614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong } 346b104340496e3a531e26c8f428c808eca0e039f50San Mehat mListeners.add(new ListenerDelegate(listener)); 347b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 348b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 349b104340496e3a531e26c8f428c808eca0e039f50San Mehat 350b104340496e3a531e26c8f428c808eca0e039f50San Mehat /** 351b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Unregisters a {@link android.os.storage.StorageEventListener StorageEventListener}. 352b104340496e3a531e26c8f428c808eca0e039f50San Mehat * 353b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @param listener A {@link android.os.storage.StorageEventListener StorageEventListener} object. 354b104340496e3a531e26c8f428c808eca0e039f50San Mehat * 355ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root * @hide 356b104340496e3a531e26c8f428c808eca0e039f50San Mehat */ 357b104340496e3a531e26c8f428c808eca0e039f50San Mehat public void unregisterListener(StorageEventListener listener) { 358b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (listener == null) { 359b104340496e3a531e26c8f428c808eca0e039f50San Mehat return; 360b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 361b104340496e3a531e26c8f428c808eca0e039f50San Mehat 362b104340496e3a531e26c8f428c808eca0e039f50San Mehat synchronized (mListeners) { 363b104340496e3a531e26c8f428c808eca0e039f50San Mehat final int size = mListeners.size(); 364b104340496e3a531e26c8f428c808eca0e039f50San Mehat for (int i=0 ; i<size ; i++) { 365b104340496e3a531e26c8f428c808eca0e039f50San Mehat ListenerDelegate l = mListeners.get(i); 366b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (l.getListener() == listener) { 367b104340496e3a531e26c8f428c808eca0e039f50San Mehat mListeners.remove(i); 368b104340496e3a531e26c8f428c808eca0e039f50San Mehat break; 369b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 370b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 3716614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong if (mListeners.size() == 0 && mBinderListener != null) { 3726614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong try { 3736614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong mMountService.unregisterListener(mBinderListener); 3746614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong } catch (RemoteException rex) { 3756614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong Log.e(TAG, "Unregister mBinderListener failed"); 3766614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong return; 3776614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong } 3786614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong } 3796614bb657929c70dad988fb14b4b91f3b9d4f7fcChuanxia Dong } 380b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 381b104340496e3a531e26c8f428c808eca0e039f50San Mehat 382b104340496e3a531e26c8f428c808eca0e039f50San Mehat /** 383b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Enables USB Mass Storage (UMS) on the device. 384ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root * 385ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root * @hide 386b104340496e3a531e26c8f428c808eca0e039f50San Mehat */ 3870eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu public void enableUsbMassStorage() { 388b104340496e3a531e26c8f428c808eca0e039f50San Mehat try { 3890eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu mMountService.setUsbMassStorageEnabled(true); 390b104340496e3a531e26c8f428c808eca0e039f50San Mehat } catch (Exception ex) { 391b104340496e3a531e26c8f428c808eca0e039f50San Mehat Log.e(TAG, "Failed to enable UMS", ex); 392b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 393b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 394b104340496e3a531e26c8f428c808eca0e039f50San Mehat 395b104340496e3a531e26c8f428c808eca0e039f50San Mehat /** 396b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Disables USB Mass Storage (UMS) on the device. 397ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root * 398ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root * @hide 399b104340496e3a531e26c8f428c808eca0e039f50San Mehat */ 4000eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu public void disableUsbMassStorage() { 401b104340496e3a531e26c8f428c808eca0e039f50San Mehat try { 4020eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu mMountService.setUsbMassStorageEnabled(false); 403b104340496e3a531e26c8f428c808eca0e039f50San Mehat } catch (Exception ex) { 404b104340496e3a531e26c8f428c808eca0e039f50San Mehat Log.e(TAG, "Failed to disable UMS", ex); 405b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 406b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 407b104340496e3a531e26c8f428c808eca0e039f50San Mehat 408b104340496e3a531e26c8f428c808eca0e039f50San Mehat /** 409b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Query if a USB Mass Storage (UMS) host is connected. 410b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @return true if UMS host is connected. 411ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root * 412ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root * @hide 413b104340496e3a531e26c8f428c808eca0e039f50San Mehat */ 414b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageConnected() { 415b104340496e3a531e26c8f428c808eca0e039f50San Mehat try { 416b104340496e3a531e26c8f428c808eca0e039f50San Mehat return mMountService.isUsbMassStorageConnected(); 417b104340496e3a531e26c8f428c808eca0e039f50San Mehat } catch (Exception ex) { 418b104340496e3a531e26c8f428c808eca0e039f50San Mehat Log.e(TAG, "Failed to get UMS connection state", ex); 419b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 420b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 421b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 422b104340496e3a531e26c8f428c808eca0e039f50San Mehat 423b104340496e3a531e26c8f428c808eca0e039f50San Mehat /** 424b104340496e3a531e26c8f428c808eca0e039f50San Mehat * Query if a USB Mass Storage (UMS) is enabled on the device. 425b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @return true if UMS host is enabled. 426ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root * 427ec7c9ff0bb1c98cb8bec3ec7bdacbae3a434fa53Kenny Root * @hide 428b104340496e3a531e26c8f428c808eca0e039f50San Mehat */ 429b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageEnabled() { 430b104340496e3a531e26c8f428c808eca0e039f50San Mehat try { 431b104340496e3a531e26c8f428c808eca0e039f50San Mehat return mMountService.isUsbMassStorageEnabled(); 432b104340496e3a531e26c8f428c808eca0e039f50San Mehat } catch (RemoteException rex) { 433b104340496e3a531e26c8f428c808eca0e039f50San Mehat Log.e(TAG, "Failed to get UMS enable state", rex); 434b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 435b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 436b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 43702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 43802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root /** 439a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * Mount an Opaque Binary Blob (OBB) file. If a <code>key</code> is 440a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * specified, it is supplied to the mounting process to be used in any 441a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * encryption used in the OBB. 442a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * <p> 44305105f7abe02b2dff91d6260b3628c8b97816babKenny Root * The OBB will remain mounted for as long as the StorageManager reference 44405105f7abe02b2dff91d6260b3628c8b97816babKenny Root * is held by the application. As soon as this reference is lost, the OBBs 445af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * in use will be unmounted. The {@link OnObbStateChangeListener} registered 446af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * with this call will receive the success or failure of this operation. 44705105f7abe02b2dff91d6260b3628c8b97816babKenny Root * <p> 448a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * <em>Note:</em> you can only mount OBB files for which the OBB tag on the 449a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * file matches a package ID that is owned by the calling program's UID. 45005105f7abe02b2dff91d6260b3628c8b97816babKenny Root * That is, shared UID applications can attempt to mount any other 451a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * application's OBB that shares its UID. 452a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * 4534fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey * @param rawPath the path to the OBB file 45405105f7abe02b2dff91d6260b3628c8b97816babKenny Root * @param key secret used to encrypt the OBB; may be <code>null</code> if no 45505105f7abe02b2dff91d6260b3628c8b97816babKenny Root * encryption was used on the OBB. 456af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * @param listener will receive the success or failure of the operation 457a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * @return whether the mount call was successfully queued or not 45802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root */ 4594fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey public boolean mountObb(String rawPath, String key, OnObbStateChangeListener listener) { 4604fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 4614fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(listener, "listener cannot be null"); 462af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 46302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root try { 4644fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final String canonicalPath = new File(rawPath).getCanonicalPath(); 465af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final int nonce = mObbActionListener.addListener(listener); 4664fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey mMountService.mountObb(rawPath, canonicalPath, key, mObbActionListener, nonce); 467a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return true; 4684fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } catch (IOException e) { 4694fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey throw new IllegalArgumentException("Failed to resolve path: " + rawPath, e); 47002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } catch (RemoteException e) { 47102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root Log.e(TAG, "Failed to mount OBB", e); 47202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 47302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 47402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return false; 47502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 47602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 47702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root /** 47805105f7abe02b2dff91d6260b3628c8b97816babKenny Root * Unmount an Opaque Binary Blob (OBB) file asynchronously. If the 47905105f7abe02b2dff91d6260b3628c8b97816babKenny Root * <code>force</code> flag is true, it will kill any application needed to 48005105f7abe02b2dff91d6260b3628c8b97816babKenny Root * unmount the given OBB (even the calling application). 48105105f7abe02b2dff91d6260b3628c8b97816babKenny Root * <p> 482af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * The {@link OnObbStateChangeListener} registered with this call will 483af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * receive the success or failure of this operation. 484a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * <p> 485a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * <em>Note:</em> you can only mount OBB files for which the OBB tag on the 486a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * file matches a package ID that is owned by the calling program's UID. 487a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * That is, shared UID applications can obtain access to any other 488a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * application's OBB that shares its UID. 48902ca31fbae9f35dd30f79de6927fae11b549391aKenny Root * <p> 490a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * 4914fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey * @param rawPath path to the OBB file 492a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * @param force whether to kill any programs using this in order to unmount 493a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * it 494af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * @param listener will receive the success or failure of the operation 495a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * @return whether the unmount call was successfully queued or not 49602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root */ 4974fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey public boolean unmountObb(String rawPath, boolean force, OnObbStateChangeListener listener) { 4984fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 4994fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(listener, "listener cannot be null"); 500af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 50102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root try { 502af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final int nonce = mObbActionListener.addListener(listener); 5034fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey mMountService.unmountObb(rawPath, force, mObbActionListener, nonce); 504a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return true; 50502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } catch (RemoteException e) { 50602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root Log.e(TAG, "Failed to mount OBB", e); 50702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 50802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 50902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return false; 51002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 51102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 512a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root /** 513a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * Check whether an Opaque Binary Blob (OBB) is mounted or not. 514a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * 5154fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey * @param rawPath path to OBB image 516a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * @return true if OBB is mounted; false if not mounted or on error 517a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root */ 5184fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey public boolean isObbMounted(String rawPath) { 5194fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 520af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 52102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root try { 5224fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return mMountService.isObbMounted(rawPath); 52302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } catch (RemoteException e) { 52402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root Log.e(TAG, "Failed to check if OBB is mounted", e); 52502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 52602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 52702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return false; 52802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 52902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 53002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root /** 531a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * Check the mounted path of an Opaque Binary Blob (OBB) file. This will 532a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * give you the path to where you can obtain access to the internals of the 533a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * OBB. 534a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * 5354fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey * @param rawPath path to OBB image 536a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * @return absolute path to mounted OBB image data or <code>null</code> if 537a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * not mounted or exception encountered trying to read status 53802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root */ 5394fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey public String getMountedObbPath(String rawPath) { 5404fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 541af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 54202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root try { 5434fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return mMountService.getMountedObbPath(rawPath); 54402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } catch (RemoteException e) { 54502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root Log.e(TAG, "Failed to find mounted path for OBB", e); 54602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 54702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 54802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return null; 54902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 550d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood 551d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood /** 552d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood * Gets the state of a volume via its mountpoint. 553d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood * @hide 554d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood */ 555d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood public String getVolumeState(String mountPoint) { 556cba928cef7d614d375253246f014c4a52bb8b913Mike Lockwood if (mMountService == null) return Environment.MEDIA_REMOVED; 557d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood try { 558d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood return mMountService.getVolumeState(mountPoint); 559d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood } catch (RemoteException e) { 560d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood Log.e(TAG, "Failed to get volume state", e); 561d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood return null; 562d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood } 563d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood } 564d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood 565d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood /** 566d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood * Returns list of all mountable volumes. 567d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood * @hide 568d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood */ 5692f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood public StorageVolume[] getVolumeList() { 570cba928cef7d614d375253246f014c4a52bb8b913Mike Lockwood if (mMountService == null) return new StorageVolume[0]; 571d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood try { 5722f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood Parcelable[] list = mMountService.getVolumeList(); 5732f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (list == null) return new StorageVolume[0]; 5742f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood int length = list.length; 5752f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood StorageVolume[] result = new StorageVolume[length]; 5762f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood for (int i = 0; i < length; i++) { 5772f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood result[i] = (StorageVolume)list[i]; 5782f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 5792f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood return result; 580d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood } catch (RemoteException e) { 581d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood Log.e(TAG, "Failed to get volume list", e); 582d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood return null; 583d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood } 584d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood } 5852f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 5862f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood /** 5872f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood * Returns list of paths for all mountable volumes. 5882f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood * @hide 5892f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood */ 5902f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood public String[] getVolumePaths() { 5912f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood StorageVolume[] volumes = getVolumeList(); 5922f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (volumes == null) return null; 5932f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood int count = volumes.length; 5942f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood String[] paths = new String[count]; 5952f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood for (int i = 0; i < count; i++) { 5962f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood paths[i] = volumes[i].getPath(); 5972f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 5982f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood return paths; 5992f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 600b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 601b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey /** {@hide} */ 602b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey public StorageVolume getPrimaryVolume() { 603b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey return getPrimaryVolume(getVolumeList()); 604b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 605b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 606b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey /** {@hide} */ 607b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey public static StorageVolume getPrimaryVolume(StorageVolume[] volumes) { 608b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey for (StorageVolume volume : volumes) { 609b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (volume.isPrimary()) { 610b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey return volume; 611b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 612b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 613b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Log.w(TAG, "No primary storage defined"); 614b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey return null; 615b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 616be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey 617be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10; 618be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500 * MB_IN_BYTES; 619be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey private static final long DEFAULT_FULL_THRESHOLD_BYTES = MB_IN_BYTES; 620be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey 621be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey /** 622742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey * Return the number of available bytes until the given path is considered 623742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey * running low on storage. 624742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey * 625742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey * @hide 626742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey */ 627742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey public long getStorageBytesUntilLow(File path) { 628742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey return path.getUsableSpace() - getStorageFullBytes(path); 629742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey } 630742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey 631742e790294b3441b79f715fe447069b63c6065dbJeff Sharkey /** 632be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey * Return the number of available bytes at which the given path is 633be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey * considered running low on storage. 634be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey * 635be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey * @hide 636be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey */ 637be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey public long getStorageLowBytes(File path) { 638be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey final long lowPercent = Settings.Global.getInt(mResolver, 639be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE, DEFAULT_THRESHOLD_PERCENTAGE); 640be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey final long lowBytes = (path.getTotalSpace() * lowPercent) / 100; 641be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey 642be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey final long maxLowBytes = Settings.Global.getLong(mResolver, 643be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES, DEFAULT_THRESHOLD_MAX_BYTES); 644be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey 645be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey return Math.min(lowBytes, maxLowBytes); 646be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey } 647be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey 648be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey /** 649be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey * Return the number of available bytes at which the given path is 650be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey * considered full. 651be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey * 652be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey * @hide 653be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey */ 654be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey public long getStorageFullBytes(File path) { 655be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES, 656be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey DEFAULT_FULL_THRESHOLD_BYTES); 657be72215c39916af9ae42332260c04b696bc73d7fJeff Sharkey } 658e8fdc541dc8c4388dc3c6d52aff70f290d7fb985Paul Lawrence 659e8fdc541dc8c4388dc3c6d52aff70f290d7fb985Paul Lawrence /// Consts to match the password types in cryptfs.h 660e8fdc541dc8c4388dc3c6d52aff70f290d7fb985Paul Lawrence /** @hide */ 661e8fdc541dc8c4388dc3c6d52aff70f290d7fb985Paul Lawrence public static final int CRYPT_TYPE_PASSWORD = 0; 662e8fdc541dc8c4388dc3c6d52aff70f290d7fb985Paul Lawrence /** @hide */ 663e8fdc541dc8c4388dc3c6d52aff70f290d7fb985Paul Lawrence public static final int CRYPT_TYPE_DEFAULT = 1; 664e8fdc541dc8c4388dc3c6d52aff70f290d7fb985Paul Lawrence /** @hide */ 665e8fdc541dc8c4388dc3c6d52aff70f290d7fb985Paul Lawrence public static final int CRYPT_TYPE_PATTERN = 2; 666e8fdc541dc8c4388dc3c6d52aff70f290d7fb985Paul Lawrence /** @hide */ 667e8fdc541dc8c4388dc3c6d52aff70f290d7fb985Paul Lawrence public static final int CRYPT_TYPE_PIN = 3; 668f839b4fcb6b179529585765517895a8c90fe315bElliott Hughes 669f839b4fcb6b179529585765517895a8c90fe315bElliott Hughes // Constants for the data available via MountService.getField. 670f839b4fcb6b179529585765517895a8c90fe315bElliott Hughes /** @hide */ 671f839b4fcb6b179529585765517895a8c90fe315bElliott Hughes public static final String SYSTEM_LOCALE_KEY = "SystemLocale"; 672f839b4fcb6b179529585765517895a8c90fe315bElliott Hughes /** @hide */ 673f839b4fcb6b179529585765517895a8c90fe315bElliott Hughes public static final String OWNER_INFO_KEY = "OwnerInfo"; 674f839b4fcb6b179529585765517895a8c90fe315bElliott Hughes /** @hide */ 675f839b4fcb6b179529585765517895a8c90fe315bElliott Hughes public static final String PATTERN_VISIBLE_KEY = "PatternVisible"; 676b104340496e3a531e26c8f428c808eca0e039f50San Mehat} 677