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