MountService.java revision 3b1abba6bbc895d63da3e82e9b158c01bd12eddd
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.server;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport com.android.internal.app.IMediaContainerService;
20c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport com.android.server.am.ActivityManagerService;
21c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
23a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ComponentName;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
27a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ServiceConnection;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
2902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.content.res.ObbInfo;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri;
3102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.os.Binder;
32a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.Environment;
33c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Handler;
345f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.HandlerThread;
35a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.IBinder;
365f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.Looper;
37c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Message;
384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehatimport android.os.RemoteException;
39fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapuimport android.os.ServiceManager;
40207e538350665cea00e1aa70b8094beca4a34e45San Mehatimport android.os.SystemClock;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties;
42a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountService;
43a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountServiceListener;
44a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountShutdownObserver;
45a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IObbActionListener;
46af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Rootimport android.os.storage.OnObbStateChangeListener;
47a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.StorageResultCode;
48a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehatimport android.util.Slog;
49a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
5038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.FileDescriptor;
5105105f7abe02b2dff91d6260b3628c8b97816babKenny Rootimport java.io.IOException;
5238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.PrintWriter;
533b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.math.BigInteger;
54735de3b38abbd6564082a819377673ee593744a6Kenny Rootimport java.security.NoSuchAlgorithmException;
553b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.InvalidKeySpecException;
563b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.KeySpec;
5722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehatimport java.util.ArrayList;
58a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.HashMap;
596cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehatimport java.util.HashSet;
6038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Iterator;
61a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.LinkedList;
62a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.List;
63a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.Map;
6438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Map.Entry;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
663b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKey;
673b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKeyFactory;
683b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.spec.PBEKeySpec;
693b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
71b104340496e3a531e26c8f428c808eca0e039f50San Mehat * MountService implements back-end services for platform storage
72b104340496e3a531e26c8f428c808eca0e039f50San Mehat * management.
73b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @hide - Applications should use android.os.storage.StorageManager
74b104340496e3a531e26c8f428c808eca0e039f50San Mehat * to access the MountService.
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
7622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehatclass MountService extends IMountService.Stub
7722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        implements INativeDaemonConnectorCallbacks {
78b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private static final boolean LOCAL_LOGD = false;
798a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu    private static final boolean DEBUG_UNMOUNT = false;
808a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu    private static final boolean DEBUG_EVENTS = false;
8102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    private static final boolean DEBUG_OBB = true;
8202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "MountService";
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
85305bcbf0c961840c4505770d084a1caacc074dbbKenny Root    private static final String VOLD_TAG = "VoldConnector";
86305bcbf0c961840c4505770d084a1caacc074dbbKenny Root
874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    /*
884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Internal vold volume state constants
894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     */
907fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    class VolumeState {
917fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Init       = -1;
927fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int NoMedia    = 0;
937fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Idle       = 1;
947fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Pending    = 2;
957fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Checking   = 3;
967fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Mounted    = 4;
977fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Unmounting = 5;
987fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Formatting = 6;
997fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Shared     = 7;
1007fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int SharedMnt  = 8;
1017fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
1027fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
1034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    /*
1044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Internal vold response code constants
1054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     */
10622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    class VoldResponseCode {
1074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 100 series - Requestion action was initiated; expect another reply
1094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         *              before proceeding with a new command.
1104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
11122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeListResult               = 110;
11222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int AsecListResult                 = 111;
113c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        public static final int StorageUsersListResult         = 112;
11422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
1154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 200 series - Requestion action has been successfully completed.
1174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
1184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int ShareStatusResult              = 210;
11922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int AsecPathResult                 = 211;
1204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int ShareEnabledResult             = 212;
12122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
1224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 400 series - Command was accepted, but the requested action
1244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         *              did not take place.
1254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
1264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedNoMedia                = 401;
1274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedMediaBlank             = 402;
1284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedMediaCorrupt           = 403;
1294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedVolNotMounted          = 404;
130d970998b0d489774ad1c5b94b47d233912f00214San Mehat        public static final int OpFailedStorageBusy            = 405;
1312d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        public static final int OpFailedStorageNotFound        = 406;
1324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 600 series - Unsolicited broadcasts.
1354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
13622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeStateChange              = 605;
13722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int ShareAvailabilityChange        = 620;
13822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeDiskInserted             = 630;
13922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeDiskRemoved              = 631;
14022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeBadRemoval               = 632;
14122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
14222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
1434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private Context                               mContext;
1444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private NativeDaemonConnector                 mConnector;
1454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private String                                mLegacyState = Environment.MEDIA_REMOVED;
1464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private PackageManagerService                 mPms;
1474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private boolean                               mUmsEnabling;
1480eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    // Used as a lock for methods that register/unregister listeners.
1490eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    final private ArrayList<MountServiceBinderListener> mListeners =
1500eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            new ArrayList<MountServiceBinderListener>();
1516a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private boolean                               mBooted = false;
1526a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private boolean                               mReady = false;
1536a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private boolean                               mSendUmsConnectedOnBoot = false;
154fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapu
1556cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    /**
1566cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat     * Private hash of currently mounted secure containers.
1570eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu     * Used as a lock in methods to manipulate secure containers.
1586cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat     */
1590eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    final private HashSet<String> mAsecMountSet = new HashSet<String>();
1606cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
16102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    /**
1623b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * The size of the crypto algorithm key in bits for OBB files. Currently
1633b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * Twofish is used which takes 128-bit keys.
1643b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     */
1653b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
1663b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
1673b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    /**
1683b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * The number of times to run SHA1 in the PBKDF2 function for OBB files.
1693b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * 1024 is reasonably secure and not too slow.
1703b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     */
1713b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    private static final int PBKDF2_HASH_ROUNDS = 1024;
1723b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
1733b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    /**
174a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * Mounted OBB tracking information. Used to track the current state of all
175a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * OBBs.
176a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     */
177735de3b38abbd6564082a819377673ee593744a6Kenny Root    final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
178a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
179a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
180a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class ObbState implements IBinder.DeathRecipient {
181af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        public ObbState(String filename, int callerUid, IObbActionListener token, int nonce)
182735de3b38abbd6564082a819377673ee593744a6Kenny Root                throws RemoteException {
183a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            this.filename = filename;
184a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            this.callerUid = callerUid;
185af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            this.token = token;
186af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            this.nonce = nonce;
187a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
188a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
189a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        // OBB source filename
190af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        String filename;
191a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
192a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        // Binder.callingUid()
19305105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final public int callerUid;
194a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
195af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        // Token of remote Binder caller
196af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IObbActionListener token;
197af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
198af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        // Identifier to pass back to the token
199af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final int nonce;
200a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
201735de3b38abbd6564082a819377673ee593744a6Kenny Root        public IBinder getBinder() {
202735de3b38abbd6564082a819377673ee593744a6Kenny Root            return token.asBinder();
203735de3b38abbd6564082a819377673ee593744a6Kenny Root        }
204735de3b38abbd6564082a819377673ee593744a6Kenny Root
205a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
206a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void binderDied() {
207a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            ObbAction action = new UnmountObbAction(this, true);
208a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
209735de3b38abbd6564082a819377673ee593744a6Kenny Root        }
210a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2115919ac6b4188285324646772501ef4b97b353cf4Kenny Root        public void link() throws RemoteException {
2125919ac6b4188285324646772501ef4b97b353cf4Kenny Root            getBinder().linkToDeath(this, 0);
2135919ac6b4188285324646772501ef4b97b353cf4Kenny Root        }
2145919ac6b4188285324646772501ef4b97b353cf4Kenny Root
2155919ac6b4188285324646772501ef4b97b353cf4Kenny Root        public void unlink() {
216735de3b38abbd6564082a819377673ee593744a6Kenny Root            getBinder().unlinkToDeath(this, 0);
217a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
21838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
21938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        @Override
22038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        public String toString() {
22138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            StringBuilder sb = new StringBuilder("ObbState{");
22238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append("filename=");
22338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(filename);
22438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(",token=");
22538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(token.toString());
22638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(",callerUid=");
22738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(callerUid);
22838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append('}');
22938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return sb.toString();
23038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
231a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
232a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
233a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // OBB Action Handler
234a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private ObbActionHandler mObbActionHandler;
235a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
236a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // OBB action handler messages
237a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_RUN_ACTION = 1;
238a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_BOUND = 2;
239a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_UNBIND = 3;
240a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_RECONNECT = 4;
241af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private static final int OBB_FLUSH_MOUNT_STATE = 5;
242a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
243a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    /*
244a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * Default Container Service information
24502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root     */
246a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
247a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
248a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
249a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
250a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
251a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class DefaultContainerConnection implements ServiceConnection {
252a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void onServiceConnected(ComponentName name, IBinder service) {
253a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
254a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "onServiceConnected");
255a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
256a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
257a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
258a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
259a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void onServiceDisconnected(ComponentName name) {
260a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
261a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "onServiceDisconnected");
262a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
263a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    };
264a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
265a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // Used in the ObbActionHandler
266a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private IMediaContainerService mContainerService = null;
26702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
26802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    // Handler messages
269c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_PM_UPDATE = 1;
270c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_PM_DONE = 2;
271c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_MS = 3;
272c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int RETRY_UNMOUNT_DELAY = 30; // in ms
273c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int MAX_UNMOUNT_RETRIES = 4;
274c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
275c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    class UnmountCallBack {
27605105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final String path;
27705105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final boolean force;
278c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        int retries;
279c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
280c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        UnmountCallBack(String path, boolean force) {
281c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            retries = 0;
282c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            this.path = path;
283c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            this.force = force;
284c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        }
2850eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
2860eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        void handleFinished() {
287a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path);
2880eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            doUnmountVolume(path, true);
2890eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
2900eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
2910eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
2920eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    class UmsEnableCallBack extends UnmountCallBack {
29305105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final String method;
2940eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
2950eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        UmsEnableCallBack(String path, String method, boolean force) {
2960eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            super(path, force);
2970eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            this.method = method;
2980eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
2990eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3000eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        @Override
3010eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        void handleFinished() {
3020eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            super.handleFinished();
3030eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            doShareUnshareVolume(path, method, true);
3040eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
305c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    }
306c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
3076ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    class ShutdownCallBack extends UnmountCallBack {
3086ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        IMountShutdownObserver observer;
3096ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        ShutdownCallBack(String path, IMountShutdownObserver observer) {
3106ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            super(path, true);
3116ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            this.observer = observer;
3126ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        }
3136ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3146ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        @Override
3156ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        void handleFinished() {
3166ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            int ret = doUnmountVolume(path, true);
3176ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            if (observer != null) {
3186ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                try {
3196ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    observer.onShutDownComplete(ret);
3206ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                } catch (RemoteException e) {
321a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.w(TAG, "RemoteException when shutting down");
3226ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                }
3236ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            }
3246ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        }
3256ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    }
3266ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3275f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler    class MountServiceHandler extends Handler {
328c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>();
329e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        boolean mUpdatingStatus = false;
3306ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3315f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        MountServiceHandler(Looper l) {
3325f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler            super(l);
3335f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        }
3345f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler
335c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        public void handleMessage(Message msg) {
336c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            switch (msg.what) {
337c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                case H_UNMOUNT_PM_UPDATE: {
338a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_UPDATE");
339c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    UnmountCallBack ucb = (UnmountCallBack) msg.obj;
340c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    mForceUnmounts.add(ucb);
341a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, " registered = " + mUpdatingStatus);
3426ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    // Register only if needed.
343e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                    if (!mUpdatingStatus) {
344a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        if (DEBUG_UNMOUNT) Slog.i(TAG, "Updating external media status on PackageManager");
345e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                        mUpdatingStatus = true;
346e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                        mPms.updateExternalMediaStatus(false, true);
347c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    }
348c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
349c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
350c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                case H_UNMOUNT_PM_DONE: {
351a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_DONE");
352a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "Updated status. Processing requests");
353e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                    mUpdatingStatus = false;
3546ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int size = mForceUnmounts.size();
3556ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int sizeArr[] = new int[size];
3566ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int sizeArrN = 0;
3577af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    // Kill processes holding references first
3587af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    ActivityManagerService ams = (ActivityManagerService)
3597af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    ServiceManager.getService("activity");
3606ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    for (int i = 0; i < size; i++) {
3616ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        UnmountCallBack ucb = mForceUnmounts.get(i);
3626ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        String path = ucb.path;
3636ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        boolean done = false;
3646ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        if (!ucb.force) {
365c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                            done = true;
366c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        } else {
3676ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            int pids[] = getStorageUsers(path);
3686ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            if (pids == null || pids.length == 0) {
3696ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                                done = true;
3706ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            } else {
3716ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                                // Eliminate system process here?
3727af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                ams.killPids(pids, "unmount media");
3737af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                // Confirm if file references have been freed.
3747af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                pids = getStorageUsers(path);
3757af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                if (pids == null || pids.length == 0) {
3767af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    done = true;
377c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                                }
378c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                            }
379c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        }
3807af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                        if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) {
3817af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            // Retry again
3827af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            Slog.i(TAG, "Retrying to kill storage users again");
3837af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            mHandler.sendMessageDelayed(
3847af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    mHandler.obtainMessage(H_UNMOUNT_PM_DONE,
3857af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                            ucb.retries++),
3867af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    RETRY_UNMOUNT_DELAY);
387c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        } else {
3886ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            if (ucb.retries >= MAX_UNMOUNT_RETRIES) {
3897af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                Slog.i(TAG, "Failed to unmount media inspite of " +
3907af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                        MAX_UNMOUNT_RETRIES + " retries. Forcibly killing processes now");
3916ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            }
3927af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            sizeArr[sizeArrN++] = i;
3937af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS,
3947af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    ucb));
395c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        }
396c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    }
3976ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    // Remove already processed elements from list.
3986ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    for (int i = (sizeArrN-1); i >= 0; i--) {
3996ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        mForceUnmounts.remove(sizeArr[i]);
4006ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    }
401c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
402c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
403c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                case H_UNMOUNT_MS : {
404a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_MS");
405c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    UnmountCallBack ucb = (UnmountCallBack) msg.obj;
4060eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                    ucb.handleFinished();
407c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
408c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
409c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            }
410c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        }
411c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    };
4125f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler    final private HandlerThread mHandlerThread;
4135f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler    final private Handler mHandler;
414c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
415207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void waitForReady() {
416207e538350665cea00e1aa70b8094beca4a34e45San Mehat        while (mReady == false) {
417207e538350665cea00e1aa70b8094beca4a34e45San Mehat            for (int retries = 5; retries > 0; retries--) {
418207e538350665cea00e1aa70b8094beca4a34e45San Mehat                if (mReady) {
419207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    return;
420207e538350665cea00e1aa70b8094beca4a34e45San Mehat                }
421207e538350665cea00e1aa70b8094beca4a34e45San Mehat                SystemClock.sleep(1000);
422207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
423a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.w(TAG, "Waiting too long for mReady!");
424207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
4251f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat    }
42602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
427207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
42991c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat            String action = intent.getAction();
43091c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
43191c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat            if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
432207e538350665cea00e1aa70b8094beca4a34e45San Mehat                mBooted = true;
43322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
434c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                /*
435c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                 * In the simulator, we need to broadcast a volume mounted event
436c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                 * to make the media scanner run.
437c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                 */
438c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
439c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                    notifyVolumeStateChange(null, "/sdcard", VolumeState.NoMedia, VolumeState.Mounted);
440c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                    return;
441c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                }
442fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                new Thread() {
443fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                    public void run() {
444fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                        try {
445fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                            String path = Environment.getExternalStorageDirectory().getPath();
4466a254403235196692b1769d2fe281b0852c0cc25San Mehat                            String state = getVolumeState(path);
4476a254403235196692b1769d2fe281b0852c0cc25San Mehat
4486a254403235196692b1769d2fe281b0852c0cc25San Mehat                            if (state.equals(Environment.MEDIA_UNMOUNTED)) {
449fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                                int rc = doMountVolume(path);
450fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                                if (rc != StorageResultCode.OperationSucceeded) {
451a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                                    Slog.e(TAG, String.format("Boot-time mount failed (%d)", rc));
452fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                                }
4536a254403235196692b1769d2fe281b0852c0cc25San Mehat                            } else if (state.equals(Environment.MEDIA_SHARED)) {
4546a254403235196692b1769d2fe281b0852c0cc25San Mehat                                /*
4556a254403235196692b1769d2fe281b0852c0cc25San Mehat                                 * Bootstrap UMS enabled state since vold indicates
4566a254403235196692b1769d2fe281b0852c0cc25San Mehat                                 * the volume is shared (runtime restart while ums enabled)
4576a254403235196692b1769d2fe281b0852c0cc25San Mehat                                 */
4586a254403235196692b1769d2fe281b0852c0cc25San Mehat                                notifyVolumeStateChange(null, path, VolumeState.NoMedia, VolumeState.Shared);
459fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                            }
4606a254403235196692b1769d2fe281b0852c0cc25San Mehat
4616a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                            /*
4626a254403235196692b1769d2fe281b0852c0cc25San Mehat                             * If UMS was connected on boot, send the connected event
4636a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                             * now that we're up.
4646a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                             */
4656a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                            if (mSendUmsConnectedOnBoot) {
4666a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                                sendUmsIntent(true);
4676a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                                mSendUmsConnectedOnBoot = false;
4686a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                            }
469fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                        } catch (Exception ex) {
470a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.e(TAG, "Boot-time mount exception", ex);
471fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                        }
472207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    }
473fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                }.start();
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private final class MountServiceBinderListener implements IBinder.DeathRecipient {
4794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        final IMountServiceListener mListener;
48091c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
4814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        MountServiceBinderListener(IMountServiceListener listener) {
4824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mListener = listener;
48302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
48491c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat        }
48591c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
4864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public void binderDied() {
487a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!");
488a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            synchronized (mListeners) {
4894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListeners.remove(this);
4904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListener.asBinder().unlinkToDeath(this, 0);
49191c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat            }
49291c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat        }
49391c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat    }
49491c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
4950eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private void doShareUnshareVolume(String path, String method, boolean enable) {
4964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        // TODO: Add support for multiple share methods
4974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (!method.equals("ums")) {
4984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            throw new IllegalArgumentException(String.format("Method %s not supported", method));
4997fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
5024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(String.format(
5034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    "volume %sshare %s %s", (enable ? "" : "un"), path, method));
5044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
505a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Failed to share/unshare", e);
50622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
509207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void updatePublicVolumeState(String path, String state) {
5104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (!path.equals(Environment.getExternalStorageDirectory().getPath())) {
511a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.w(TAG, "Multiple volumes not currently supported");
5127fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            return;
5137fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
514b104340496e3a531e26c8f428c808eca0e039f50San Mehat
515b104340496e3a531e26c8f428c808eca0e039f50San Mehat        if (mLegacyState.equals(state)) {
516a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.w(TAG, String.format("Duplicate state transition (%s -> %s)", mLegacyState, state));
517b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return;
518b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
519af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
5208a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        if (Environment.MEDIA_UNMOUNTED.equals(state)) {
521af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            // Tell the package manager the media is gone.
522e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            mPms.updateExternalMediaStatus(false, false);
523af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
524af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            /*
525af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * Some OBBs might have been unmounted when this volume was
526af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * unmounted, so send a message to the handler to let it know to
527af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * remove those from the list of mounted OBBS.
528af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             */
529af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_FLUSH_MOUNT_STATE,
530af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    path));
5318a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        } else if (Environment.MEDIA_MOUNTED.equals(state)) {
532af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            // Tell the package manager the media is available for use.
533e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            mPms.updateExternalMediaStatus(true, false);
5348a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
53538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
5364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        String oldState = mLegacyState;
5374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        mLegacyState = state;
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
5404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for (int i = mListeners.size() -1; i >= 0; i--) {
5414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                MountServiceBinderListener bl = mListeners.get(i);
5424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                try {
543b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    bl.mListener.onStorageStateChanged(path, oldState, state);
5444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (RemoteException rex) {
545a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener dead");
5464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(i);
5474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (Exception ex) {
548a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener failed", ex);
5494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
55422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    /**
55522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     *
55622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     * Callback from NativeDaemonConnector
55722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     */
55822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    public void onDaemonConnected() {
5595b77dab23469273d41f9c530d947ac055765e6eaSan Mehat        /*
5605b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         * Since we'll be calling back into the NativeDaemonConnector,
5615b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         * we need to do our work in a new thread.
5625b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         */
5637fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        new Thread() {
5647fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            public void run() {
5655b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                /**
5665b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                 * Determine media state and UMS detection status
5675b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                 */
5685b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                String path = Environment.getExternalStorageDirectory().getPath();
5695b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                String state = Environment.MEDIA_REMOVED;
5705b77dab23469273d41f9c530d947ac055765e6eaSan Mehat
5717fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                try {
5725b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                    String[] vols = mConnector.doListCommand(
5734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        "volume list", VoldResponseCode.VolumeListResult);
5745b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                    for (String volstr : vols) {
5755b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        String[] tok = volstr.split(" ");
5765b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        // FMT: <label> <mountpoint> <state>
5775b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        if (!tok[1].equals(path)) {
578a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.w(TAG, String.format(
5795b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                                    "Skipping unknown volume '%s'",tok[1]));
5805b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            continue;
5815b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        }
5825b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        int st = Integer.parseInt(tok[2]);
5835b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        if (st == VolumeState.NoMedia) {
5845b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_REMOVED;
5855b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Idle) {
586207e538350665cea00e1aa70b8094beca4a34e45San Mehat                            state = Environment.MEDIA_UNMOUNTED;
5875b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Mounted) {
5885b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_MOUNTED;
589a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.i(TAG, "Media already mounted on daemon connection");
5905b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Shared) {
5915b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_SHARED;
592a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.i(TAG, "Media shared on daemon connection");
5935b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else {
5945b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            throw new Exception(String.format("Unexpected state %d", st));
5957fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                        }
5967fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                    }
597c2a39471642e31d7350910612e40d078b825173aSan Mehat                    if (state != null) {
598a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state);
599c2a39471642e31d7350910612e40d078b825173aSan Mehat                        updatePublicVolumeState(path, state);
600c2a39471642e31d7350910612e40d078b825173aSan Mehat                    }
6015b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                } catch (Exception e) {
602a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Error processing initial volume state", e);
6035b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                    updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
6047fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                }
6057fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
6067fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                try {
607207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    boolean avail = doGetShareMethodAvailable("ums");
6087fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                    notifyShareAvailabilityChange("ums", avail);
6097fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                } catch (Exception ex) {
610a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.w(TAG, "Failed to get share availability");
6117fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                }
612207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
613207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Now that we've done our initialization, release
614207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * the hounds!
615207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
616207e538350665cea00e1aa70b8094beca4a34e45San Mehat                mReady = true;
6177fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            }
6187fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }.start();
6197fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
6207fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
62122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    /**
62222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     * Callback from NativeDaemonConnector
62322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     */
62422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    public boolean onEvent(int code, String raw, String[] cooked) {
6254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        Intent in = null;
6264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
6278a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        if (DEBUG_EVENTS) {
6288a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            StringBuilder builder = new StringBuilder();
6298a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            builder.append("onEvent::");
6308a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            builder.append(" raw= " + raw);
6318a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            if (cooked != null) {
6328a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                builder.append(" cooked = " );
6338a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                for (String str : cooked) {
6348a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                    builder.append(" " + str);
6358a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                }
6368a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            }
637a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.i(TAG, builder.toString());
6388a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
63922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        if (code == VoldResponseCode.VolumeStateChange) {
6404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            /*
6414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * One of the volumes we're managing has changed state.
6424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * Format: "NNN Volume <label> <path> state changed
6434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * from <old_#> (<old_str>) to <new_#> (<new_str>)"
6444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             */
64522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            notifyVolumeStateChange(
64622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat                    cooked[2], cooked[3], Integer.parseInt(cooked[7]),
64722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat                            Integer.parseInt(cooked[10]));
64822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        } else if (code == VoldResponseCode.ShareAvailabilityChange) {
64922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Share method <method> now <available|unavailable>
65022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            boolean avail = false;
65122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            if (cooked[5].equals("available")) {
65222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat                avail = true;
65322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            }
65422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            notifyShareAvailabilityChange(cooked[3], avail);
6554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } else if ((code == VoldResponseCode.VolumeDiskInserted) ||
6564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                   (code == VoldResponseCode.VolumeDiskRemoved) ||
6574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                   (code == VoldResponseCode.VolumeBadRemoval)) {
65822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
65922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
66022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
6614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            final String label = cooked[2];
6624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            final String path = cooked[3];
6634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            int major = -1;
6644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            int minor = -1;
6654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
6664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            try {
6674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                String devComp = cooked[6].substring(1, cooked[6].length() -1);
6684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                String[] devTok = devComp.split(":");
6694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                major = Integer.parseInt(devTok[0]);
6704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                minor = Integer.parseInt(devTok[1]);
6714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } catch (Exception ex) {
672a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to parse major/minor", ex);
6734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
6744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
6754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            if (code == VoldResponseCode.VolumeDiskInserted) {
6764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                new Thread() {
6774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    public void run() {
6784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        try {
6794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                            int rc;
680b104340496e3a531e26c8f428c808eca0e039f50San Mehat                            if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
681a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                                Slog.w(TAG, String.format("Insertion mount failed (%d)", rc));
6824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                            }
6834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        } catch (Exception ex) {
684a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.w(TAG, "Failed to mount media on insertion", ex);
6854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        }
6864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    }
6874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }.start();
6884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else if (code == VoldResponseCode.VolumeDiskRemoved) {
6894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /*
6904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                 * This event gets trumped if we're already in BAD_REMOVAL state
6914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                 */
6924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
6934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    return true;
6944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
6954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /* Send the media unmounted event first */
696a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
6974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
6984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
6994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mContext.sendBroadcast(in);
7004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
701a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed");
7024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
7034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                in = new Intent(Intent.ACTION_MEDIA_REMOVED, Uri.parse("file://" + path));
7044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else if (code == VoldResponseCode.VolumeBadRemoval) {
705a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
7064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /* Send the media unmounted event first */
7074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
7084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
7094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mContext.sendBroadcast(in);
7104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
711a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal");
7124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);
7134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                in = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL, Uri.parse("file://" + path));
7144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else {
715a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Unknown code {%d}", code));
7164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
71722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        } else {
71822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            return false;
71922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
7204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
7214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (in != null) {
7224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mContext.sendBroadcast(in);
7235f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        }
7245f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        return true;
72522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
72622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
727207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void notifyVolumeStateChange(String label, String path, int oldState, int newState) {
7284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        String vs = getVolumeState(path);
729a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChanged::" + vs);
7304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
7314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        Intent in = null;
7327fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
733bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood        if (oldState == VolumeState.Shared && newState != oldState) {
734a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent");
735bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood            mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_UNSHARED,
736bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood                                                Uri.parse("file://" + path)));
737bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood        }
738bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood
7397fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        if (newState == VolumeState.Init) {
7407fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.NoMedia) {
7417fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            // NoMedia is handled via Disk Remove events
7427fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Idle) {
7435fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat            /*
7445fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or
7455fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             * if we're in the process of enabling UMS
7465fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             */
7474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            if (!vs.equals(
7484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    Environment.MEDIA_BAD_REMOVAL) && !vs.equals(
7494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                            Environment.MEDIA_NOFS) && !vs.equals(
7500eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                                    Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) {
751a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable");
7524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
7534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
7547fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            }
7557fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Pending) {
7567fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Checking) {
757a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking");
7584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            updatePublicVolumeState(path, Environment.MEDIA_CHECKING);
7594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            in = new Intent(Intent.ACTION_MEDIA_CHECKING, Uri.parse("file://" + path));
7607fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Mounted) {
761a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted");
7624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            updatePublicVolumeState(path, Environment.MEDIA_MOUNTED);
7634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            in = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + path));
7644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            in.putExtra("read-only", false);
7657fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Unmounting) {
7664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            in = new Intent(Intent.ACTION_MEDIA_EJECT, Uri.parse("file://" + path));
7677fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Formatting) {
7687fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Shared) {
769a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted");
7704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            /* Send the media unmounted event first */
7714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
7724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
7734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mContext.sendBroadcast(in);
7744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
775a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared");
7764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            updatePublicVolumeState(path, Environment.MEDIA_SHARED);
7774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            in = new Intent(Intent.ACTION_MEDIA_SHARED, Uri.parse("file://" + path));
778a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent");
7797fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.SharedMnt) {
780a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Live shared mounts not supported yet!");
7814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            return;
7827fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else {
783a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Unhandled VolumeState {" + newState + "}");
7847fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
7857fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
7864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (in != null) {
7874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mContext.sendBroadcast(in);
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
791207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private boolean doGetShareMethodAvailable(String method) {
79285fb20665feadda526ad422c093b859e8c4d40bcKenny Root        ArrayList<String> rsp;
793a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
79485fb20665feadda526ad422c093b859e8c4d40bcKenny Root            rsp = mConnector.doCommand("share status " + method);
795a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException ex) {
796a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            Slog.e(TAG, "Failed to determine whether share method " + method + " is available.");
797a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            return false;
798a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
799207e538350665cea00e1aa70b8094beca4a34e45San Mehat
800207e538350665cea00e1aa70b8094beca4a34e45San Mehat        for (String line : rsp) {
801a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            String[] tok = line.split(" ");
802a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            if (tok.length < 3) {
803a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                Slog.e(TAG, "Malformed response to share status " + method);
804a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                return false;
805a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            }
806a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root
807207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code;
808207e538350665cea00e1aa70b8094beca4a34e45San Mehat            try {
809207e538350665cea00e1aa70b8094beca4a34e45San Mehat                code = Integer.parseInt(tok[0]);
810207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } catch (NumberFormatException nfe) {
811a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
812207e538350665cea00e1aa70b8094beca4a34e45San Mehat                return false;
813207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
814207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.ShareStatusResult) {
815207e538350665cea00e1aa70b8094beca4a34e45San Mehat                if (tok[2].equals("available"))
816207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    return true;
817207e538350665cea00e1aa70b8094beca4a34e45San Mehat                return false;
818207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
819a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Unexpected response code %d", code));
820207e538350665cea00e1aa70b8094beca4a34e45San Mehat                return false;
821207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
822207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
823a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        Slog.e(TAG, "Got an empty response");
824207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return false;
825207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
826207e538350665cea00e1aa70b8094beca4a34e45San Mehat
827207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private int doMountVolume(String path) {
828b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
829207e538350665cea00e1aa70b8094beca4a34e45San Mehat
830a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path);
831207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
832207e538350665cea00e1aa70b8094beca4a34e45San Mehat            mConnector.doCommand(String.format("volume mount %s", path));
833207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
834207e538350665cea00e1aa70b8094beca4a34e45San Mehat            /*
835207e538350665cea00e1aa70b8094beca4a34e45San Mehat             * Mount failed for some reason
836207e538350665cea00e1aa70b8094beca4a34e45San Mehat             */
837207e538350665cea00e1aa70b8094beca4a34e45San Mehat            Intent in = null;
838207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
839207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedNoMedia) {
840207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
841207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Attempt to mount but no media inserted
842207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
843b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedNoMedia;
844207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaBlank) {
845a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs");
846207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
847207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Media is blank or does not contain a supported filesystem
848207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
849207e538350665cea00e1aa70b8094beca4a34e45San Mehat                updatePublicVolumeState(path, Environment.MEDIA_NOFS);
850207e538350665cea00e1aa70b8094beca4a34e45San Mehat                in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path));
851b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedMediaBlank;
852207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
853a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state media corrupt");
854207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
855207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Volume consistency check failed
856207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
857207e538350665cea00e1aa70b8094beca4a34e45San Mehat                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
858207e538350665cea00e1aa70b8094beca4a34e45San Mehat                in = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path));
859b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedMediaCorrupt;
860207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
861b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedInternalError;
862207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
863207e538350665cea00e1aa70b8094beca4a34e45San Mehat
864207e538350665cea00e1aa70b8094beca4a34e45San Mehat            /*
865207e538350665cea00e1aa70b8094beca4a34e45San Mehat             * Send broadcast intent (if required for the failure)
866207e538350665cea00e1aa70b8094beca4a34e45San Mehat             */
867207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (in != null) {
868207e538350665cea00e1aa70b8094beca4a34e45San Mehat                mContext.sendBroadcast(in);
869207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
870207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
871207e538350665cea00e1aa70b8094beca4a34e45San Mehat
872207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return rc;
873207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
874207e538350665cea00e1aa70b8094beca4a34e45San Mehat
875c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    /*
876c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * If force is not set, we do not unmount if there are
877c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * processes holding references to the volume about to be unmounted.
878c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * If force is set, all the processes holding references need to be
879c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * killed via the ActivityManager before actually unmounting the volume.
880c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * This might even take a while and might be retried after timed delays
881c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * to make sure we dont end up in an instable state and kill some core
882c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * processes.
883c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     */
884d970998b0d489774ad1c5b94b47d233912f00214San Mehat    private int doUnmountVolume(String path, boolean force) {
88559443a673a736978361dc341f41ce4e9dae053a0San Mehat        if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
886207e538350665cea00e1aa70b8094beca4a34e45San Mehat            return VoldResponseCode.OpFailedVolNotMounted;
887207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
888aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
889aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
890aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
891aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
892aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
893aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
894aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
895aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
896aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
897c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        // Redundant probably. But no harm in updating state again.
898e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        mPms.updateExternalMediaStatus(false, false);
899207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
900d970998b0d489774ad1c5b94b47d233912f00214San Mehat            mConnector.doCommand(String.format(
901d970998b0d489774ad1c5b94b47d233912f00214San Mehat                    "volume unmount %s%s", path, (force ? " force" : "")));
902e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            // We unmounted the volume. None of the asec containers are available now.
903e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            synchronized (mAsecMountSet) {
904e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                mAsecMountSet.clear();
905e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            }
906b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return StorageResultCode.OperationSucceeded;
907207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
908207e538350665cea00e1aa70b8094beca4a34e45San Mehat            // Don't worry about mismatch in PackageManager since the
909207e538350665cea00e1aa70b8094beca4a34e45San Mehat            // call back will handle the status changes any way.
910207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
911207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedVolNotMounted) {
912a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageNotMounted;
913d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else if (code == VoldResponseCode.OpFailedStorageBusy) {
914d970998b0d489774ad1c5b94b47d233912f00214San Mehat                return StorageResultCode.OperationFailedStorageBusy;
915207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
916b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedInternalError;
917207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
918207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
919207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
920207e538350665cea00e1aa70b8094beca4a34e45San Mehat
921207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private int doFormatVolume(String path) {
922207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
923207e538350665cea00e1aa70b8094beca4a34e45San Mehat            String cmd = String.format("volume format %s", path);
924207e538350665cea00e1aa70b8094beca4a34e45San Mehat            mConnector.doCommand(cmd);
925b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return StorageResultCode.OperationSucceeded;
926207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
927207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
928207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedNoMedia) {
929b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedNoMedia;
930207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
931b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedMediaCorrupt;
932207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
933b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedInternalError;
934207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
935207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
936207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
937207e538350665cea00e1aa70b8094beca4a34e45San Mehat
938b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private boolean doGetVolumeShared(String path, String method) {
939b104340496e3a531e26c8f428c808eca0e039f50San Mehat        String cmd = String.format("volume shared %s %s", path, method);
940a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        ArrayList<String> rsp;
941a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root
942a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
943a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            rsp = mConnector.doCommand(cmd);
944a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException ex) {
945a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            Slog.e(TAG, "Failed to read response to volume shared " + path + " " + method);
946a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            return false;
947a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
948b104340496e3a531e26c8f428c808eca0e039f50San Mehat
949b104340496e3a531e26c8f428c808eca0e039f50San Mehat        for (String line : rsp) {
950a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            String[] tok = line.split(" ");
951a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            if (tok.length < 3) {
952a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                Slog.e(TAG, "Malformed response to volume shared " + path + " " + method + " command");
953a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                return false;
954a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            }
955a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root
956b104340496e3a531e26c8f428c808eca0e039f50San Mehat            int code;
957b104340496e3a531e26c8f428c808eca0e039f50San Mehat            try {
958b104340496e3a531e26c8f428c808eca0e039f50San Mehat                code = Integer.parseInt(tok[0]);
959b104340496e3a531e26c8f428c808eca0e039f50San Mehat            } catch (NumberFormatException nfe) {
960a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
961b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return false;
962b104340496e3a531e26c8f428c808eca0e039f50San Mehat            }
963b104340496e3a531e26c8f428c808eca0e039f50San Mehat            if (code == VoldResponseCode.ShareEnabledResult) {
964a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                return "enabled".equals(tok[2]);
965b104340496e3a531e26c8f428c808eca0e039f50San Mehat            } else {
966a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Unexpected response code %d", code));
967b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return false;
968b104340496e3a531e26c8f428c808eca0e039f50San Mehat            }
969b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
970a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        Slog.e(TAG, "Got an empty response");
971b104340496e3a531e26c8f428c808eca0e039f50San Mehat        return false;
972b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
973b104340496e3a531e26c8f428c808eca0e039f50San Mehat
974207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void notifyShareAvailabilityChange(String method, final boolean avail) {
9757fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        if (!method.equals("ums")) {
976a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat           Slog.w(TAG, "Ignoring unsupported share method {" + method + "}");
9777fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat           return;
9787fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
9791f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat
9804270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
9814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for (int i = mListeners.size() -1; i >= 0; i--) {
9824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                MountServiceBinderListener bl = mListeners.get(i);
9831f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                try {
984b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    bl.mListener.onUsbMassStorageConnectionChanged(avail);
9854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (RemoteException rex) {
986a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener dead");
9874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(i);
9881f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                } catch (Exception ex) {
989a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener failed", ex);
9901f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                }
9911f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat            }
9924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        }
9937fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
994207e538350665cea00e1aa70b8094beca4a34e45San Mehat        if (mBooted == true) {
9956a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat            sendUmsIntent(avail);
9966a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat        } else {
9976a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat            mSendUmsConnectedOnBoot = avail;
9981f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat        }
9992fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat
10002fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat        final String path = Environment.getExternalStorageDirectory().getPath();
10012fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat        if (avail == false && getVolumeState(path).equals(Environment.MEDIA_SHARED)) {
10022fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            /*
10032fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat             * USB mass storage disconnected while enabled
10042fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat             */
10052fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            new Thread() {
10062fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                public void run() {
10072fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    try {
10082fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        int rc;
1009a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        Slog.w(TAG, "Disabling UMS after cable disconnect");
10102fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        doShareUnshareVolume(path, "ums", false);
10112fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
1012a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.e(TAG, String.format(
10132fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                                    "Failed to remount {%s} on UMS enabled-disconnect (%d)",
10142fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                                            path, rc));
10152fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        }
10162fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    } catch (Exception ex) {
1017a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        Slog.w(TAG, "Failed to mount media on UMS enabled-disconnect", ex);
10182fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    }
10192fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                }
10202fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            }.start();
10212fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat        }
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10246a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private void sendUmsIntent(boolean c) {
10256a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat        mContext.sendBroadcast(
10266a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                new Intent((c ? Intent.ACTION_UMS_CONNECTED : Intent.ACTION_UMS_DISCONNECTED)));
10276a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    }
10286a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat
1029207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void validatePermission(String perm) {
10304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
10314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            throw new SecurityException(String.format("Requires %s permission", perm));
10324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        }
10337fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
10347fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1036207e538350665cea00e1aa70b8094beca4a34e45San Mehat     * Constructs a new MountService instance
1037207e538350665cea00e1aa70b8094beca4a34e45San Mehat     *
1038207e538350665cea00e1aa70b8094beca4a34e45San Mehat     * @param context  Binder context for this service
1039207e538350665cea00e1aa70b8094beca4a34e45San Mehat     */
1040207e538350665cea00e1aa70b8094beca4a34e45San Mehat    public MountService(Context context) {
1041207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mContext = context;
1042207e538350665cea00e1aa70b8094beca4a34e45San Mehat
1043207e538350665cea00e1aa70b8094beca4a34e45San Mehat        // XXX: This will go away soon in favor of IMountServiceObserver
1044207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mPms = (PackageManagerService) ServiceManager.getService("package");
1045207e538350665cea00e1aa70b8094beca4a34e45San Mehat
1046207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mContext.registerReceiver(mBroadcastReceiver,
1047207e538350665cea00e1aa70b8094beca4a34e45San Mehat                new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
1048207e538350665cea00e1aa70b8094beca4a34e45San Mehat
10495f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandlerThread = new HandlerThread("MountService");
10505f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandlerThread.start();
10515f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandler = new MountServiceHandler(mHandlerThread.getLooper());
10525f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler
1053a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        // Add OBB Action Handler to MountService thread.
1054a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());
1055a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1056c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen        /*
1057c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen         * Vold does not run in the simulator, so pretend the connector thread
1058c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen         * ran and did its thing.
1059c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen         */
1060c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen        if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
1061c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen            mReady = true;
1062c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen            mUmsEnabling = true;
1063c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen            return;
1064c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen        }
1065c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen
1066305bcbf0c961840c4505770d084a1caacc074dbbKenny Root        /*
1067305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * Create the connection to vold with a maximum queue of twice the
1068305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * amount of containers we'd ever expect to have. This keeps an
1069305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * "asec list" from blocking a thread repeatedly.
1070305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         */
1071305bcbf0c961840c4505770d084a1caacc074dbbKenny Root        mConnector = new NativeDaemonConnector(this, "vold",
1072305bcbf0c961840c4505770d084a1caacc074dbbKenny Root                PackageManagerService.MAX_CONTAINERS * 2, VOLD_TAG);
1073207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mReady = false;
1074305bcbf0c961840c4505770d084a1caacc074dbbKenny Root        Thread thread = new Thread(mConnector, VOLD_TAG);
1075207e538350665cea00e1aa70b8094beca4a34e45San Mehat        thread.start();
1076207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
1077207e538350665cea00e1aa70b8094beca4a34e45San Mehat
1078207e538350665cea00e1aa70b8094beca4a34e45San Mehat    /**
10794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Exposed API calls below here
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10817fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
10824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public void registerListener(IMountServiceListener listener) {
10834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
10844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            MountServiceBinderListener bl = new MountServiceBinderListener(listener);
10854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            try {
10864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                listener.asBinder().linkToDeath(bl, 0);
10874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListeners.add(bl);
10884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } catch (RemoteException rex) {
1089a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to link to listener death");
10904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
10917fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public void unregisterListener(IMountServiceListener listener) {
10954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
10964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for(MountServiceBinderListener bl : mListeners) {
10974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                if (bl.mListener == listener) {
10984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(mListeners.indexOf(bl));
10994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    return;
11004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
11014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11056ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    public void shutdown(final IMountShutdownObserver observer) {
11064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.SHUTDOWN);
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1108a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        Slog.i(TAG, "Shutting down");
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        String path = Environment.getExternalStorageDirectory().getPath();
11114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        String state = getVolumeState(path);
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (state.equals(Environment.MEDIA_SHARED)) {
11144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            /*
11154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * If the media is currently shared, unshare it.
11164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * XXX: This is still dangerous!. We should not
11174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * be rebooting at *all* if UMS is enabled, since
11184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * the UMS host could have dirty FAT cache entries
11194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * yet to flush.
11204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             */
11210eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            setUsbMassStorageEnabled(false);
11224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } else if (state.equals(Environment.MEDIA_CHECKING)) {
11234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            /*
11244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * If the media is being checked, then we need to wait for
11254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * it to complete before being able to proceed.
11264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             */
11274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            // XXX: @hackbod - Should we disable the ANR timer here?
11284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            int retries = 30;
11294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
11304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                try {
11314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    Thread.sleep(1000);
11324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (InterruptedException iex) {
1133a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Interrupted while waiting for media", iex);
11344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    break;
11354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
11364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                state = Environment.getExternalStorageState();
11374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
11384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            if (retries == 0) {
1139a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Timed out waiting for media to check");
11404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
11417fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
11427fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
11434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (state.equals(Environment.MEDIA_MOUNTED)) {
11446ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            // Post a unmount message.
11456ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            ShutdownCallBack ucb = new ShutdownCallBack(path, observer);
11466ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
11471f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat        }
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11500eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private boolean getUmsEnabling() {
11510eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        synchronized (mListeners) {
11520eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            return mUmsEnabling;
11530eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
11540eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
11550eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
11560eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private void setUmsEnabling(boolean enable) {
11570eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        synchronized (mListeners) {
11580eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            mUmsEnabling = true;
11590eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
11600eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
11610eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
1162b104340496e3a531e26c8f428c808eca0e039f50San Mehat    public boolean isUsbMassStorageConnected() {
1163207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
11647fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
11650eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (getUmsEnabling()) {
1166b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return true;
1167b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
1168b104340496e3a531e26c8f428c808eca0e039f50San Mehat        return doGetShareMethodAvailable("ums");
11694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11710eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    public void setUsbMassStorageEnabled(boolean enable) {
1172207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
11730eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
11740eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
11750eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        // TODO: Add support for multiple share methods
1176b104340496e3a531e26c8f428c808eca0e039f50San Mehat
11770eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        /*
11780eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         * If the volume is mounted and we're enabling then unmount it
11790eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         */
11800eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        String path = Environment.getExternalStorageDirectory().getPath();
11810eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        String vs = getVolumeState(path);
11820eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        String method = "ums";
11830eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
11840eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            // Override for isUsbMassStorageEnabled()
11850eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            setUmsEnabling(enable);
11860eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true);
11870eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb));
11880eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            // Clear override
11890eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            setUmsEnabling(false);
11900eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
11910eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        /*
11920eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         * If we disabled UMS then mount the volume
11930eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         */
11940eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (!enable) {
11950eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            doShareUnshareVolume(path, method, enable);
11960eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
1197a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to remount " + path +
11980eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                        " after disabling share method " + method);
11990eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                /*
12000eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * Even though the mount failed, the unshare didn't so don't indicate an error.
12010eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * The mountVolume() call will have set the storage state and sent the necessary
12020eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * broadcasts.
12030eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 */
12040eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            }
12050eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
12064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1208b104340496e3a531e26c8f428c808eca0e039f50San Mehat    public boolean isUsbMassStorageEnabled() {
1209207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1210b104340496e3a531e26c8f428c808eca0e039f50San Mehat        return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums");
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * @return state of the volume at the specified mount point
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String getVolumeState(String mountPoint) {
12174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
12184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * XXX: Until we have multiple volume discovery, just hardwire
12194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * this to /sdcard
12204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
12214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) {
1222a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
12234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            throw new IllegalArgumentException();
12244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        }
12254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
12264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return mLegacyState;
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
12294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int mountVolume(String path) {
12304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1232207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1233207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return doMountVolume(path);
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1236c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    public void unmountVolume(String path, boolean force) {
12374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1238207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12408a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        String volState = getVolumeState(path);
1241a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path + " force = " + force);
12428a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        if (Environment.MEDIA_UNMOUNTED.equals(volState) ||
12438a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_REMOVED.equals(volState) ||
12448a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_SHARED.equals(volState) ||
12458a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_UNMOUNTABLE.equals(volState)) {
12468a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            // Media already unmounted or cannot be unmounted.
12478a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            // TODO return valid return code when adding observer call back.
12488a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            return;
12498a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
1250c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        UnmountCallBack ucb = new UnmountCallBack(path, force);
1251c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
12524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int formatVolume(String path) {
12554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1256207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1258207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return doFormatVolume(path);
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12603697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1261c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat    public int []getStorageUsers(String path) {
1262c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1263c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        waitForReady();
1264c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        try {
1265c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            String[] r = mConnector.doListCommand(
1266c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                    String.format("storage users %s", path),
1267c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                            VoldResponseCode.StorageUsersListResult);
1268c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            // FMT: <pid> <process name>
1269c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            int[] data = new int[r.length];
1270c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            for (int i = 0; i < r.length; i++) {
1271c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                String []tok = r[i].split(" ");
1272c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                try {
1273c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                    data[i] = Integer.parseInt(tok[0]);
1274c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                } catch (NumberFormatException nfe) {
1275a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
1276c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                    return new int[0];
1277c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                }
1278c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            }
1279c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            return data;
1280c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        } catch (NativeDaemonConnectorException e) {
1281a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Failed to retrieve storage users list", e);
1282c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            return new int[0];
1283c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        }
1284c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat    }
1285c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat
1286b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private void warnOnNotMounted() {
1287b104340496e3a531e26c8f428c808eca0e039f50San Mehat        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
1288a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.w(TAG, "getSecureContainerList() called when storage not mounted");
1289b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
1290b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
1291b104340496e3a531e26c8f428c808eca0e039f50San Mehat
12924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String[] getSecureContainerList() {
12934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
1294207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1295b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1296f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
12974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
12984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult);
12994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
13004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            return new String[0];
130102735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
13023697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
13033697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
13044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int createSecureContainer(String id, int sizeMb, String fstype,
13054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                                    String key, int ownerUid) {
13064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_CREATE);
1307207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1308b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
13094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1310b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
13114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        String cmd = String.format("asec create %s %d %s %s %d", id, sizeMb, fstype, key, ownerUid);
13124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
13134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(cmd);
13144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1315b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
131602735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1317a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1318a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        if (rc == StorageResultCode.OperationSucceeded) {
1319a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            synchronized (mAsecMountSet) {
1320a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                mAsecMountSet.add(id);
1321a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1322a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
13234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
13243697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
13253697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
13264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int finalizeSecureContainer(String id) {
13274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_CREATE);
1328b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
13294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1330b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
13314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
13324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(String.format("asec finalize %s", id));
1333a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            /*
1334a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             * Finalization does a remount, so no need
1335a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             * to update mAsecMountSet
1336a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             */
13374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1338b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
133902735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
13404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
13413697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
13423697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1343d970998b0d489774ad1c5b94b47d233912f00214San Mehat    public int destroySecureContainer(String id, boolean force) {
13444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_DESTROY);
1345207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1346b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1347f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
1348aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
1349aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
1350aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
1351aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
1352aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
1353aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
1354aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
1355aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
1356b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
13574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1358d970998b0d489774ad1c5b94b47d233912f00214San Mehat            mConnector.doCommand(String.format("asec destroy %s%s", id, (force ? " force" : "")));
13594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1360d970998b0d489774ad1c5b94b47d233912f00214San Mehat            int code = e.getCode();
1361d970998b0d489774ad1c5b94b47d233912f00214San Mehat            if (code == VoldResponseCode.OpFailedStorageBusy) {
1362d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedStorageBusy;
1363d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else {
1364d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedInternalError;
1365d970998b0d489774ad1c5b94b47d233912f00214San Mehat            }
136602735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1367a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1368a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        if (rc == StorageResultCode.OperationSucceeded) {
1369a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            synchronized (mAsecMountSet) {
1370a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                if (mAsecMountSet.contains(id)) {
1371a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                    mAsecMountSet.remove(id);
1372a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                }
1373a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1374a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1375a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
13764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
13773697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
13783697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
13794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int mountSecureContainer(String id, String key, int ownerUid) {
13804270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
1381207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1382b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
13834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1384a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        synchronized (mAsecMountSet) {
1385a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            if (mAsecMountSet.contains(id)) {
1386a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageMounted;
1387a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1388a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1389a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1390b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
13914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        String cmd = String.format("asec mount %s %s %d", id, key, ownerUid);
13924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
13934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(cmd);
13944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1395f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            int code = e.getCode();
1396f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            if (code != VoldResponseCode.OpFailedStorageBusy) {
1397f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root                rc = StorageResultCode.OperationFailedInternalError;
1398f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            }
139902735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
14006cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
14016cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        if (rc == StorageResultCode.OperationSucceeded) {
14026cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            synchronized (mAsecMountSet) {
14036cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat                mAsecMountSet.add(id);
14046cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
14056cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
14064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
14073697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
14083697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1409d970998b0d489774ad1c5b94b47d233912f00214San Mehat    public int unmountSecureContainer(String id, boolean force) {
14104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
1411207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1412b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
14134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
14146cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        synchronized (mAsecMountSet) {
14156cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            if (!mAsecMountSet.contains(id)) {
1416a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageNotMounted;
14176cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
14186cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat         }
14196cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
1420aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
1421aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
1422aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
1423aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
1424aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
1425aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
1426aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
1427aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
1428b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
1429d970998b0d489774ad1c5b94b47d233912f00214San Mehat        String cmd = String.format("asec unmount %s%s", id, (force ? " force" : ""));
14304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
14314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(cmd);
14324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1433d970998b0d489774ad1c5b94b47d233912f00214San Mehat            int code = e.getCode();
1434d970998b0d489774ad1c5b94b47d233912f00214San Mehat            if (code == VoldResponseCode.OpFailedStorageBusy) {
1435d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedStorageBusy;
1436d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else {
1437d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedInternalError;
1438d970998b0d489774ad1c5b94b47d233912f00214San Mehat            }
143902735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
14406cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
14416cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        if (rc == StorageResultCode.OperationSucceeded) {
14426cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            synchronized (mAsecMountSet) {
14436cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat                mAsecMountSet.remove(id);
14446cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
14456cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
14464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
14479dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat    }
14489dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat
14496cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    public boolean isSecureContainerMounted(String id) {
14506cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
14516cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        waitForReady();
14526cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        warnOnNotMounted();
14536cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
14546cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        synchronized (mAsecMountSet) {
14556cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            return mAsecMountSet.contains(id);
14566cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
14576cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    }
14586cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
14594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int renameSecureContainer(String oldId, String newId) {
14604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_RENAME);
1461207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1462b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
14634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1464a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        synchronized (mAsecMountSet) {
146585451ee15fdf6cae371dc3005441988c7d426401San Mehat            /*
146685451ee15fdf6cae371dc3005441988c7d426401San Mehat             * Because a mounted container has active internal state which cannot be
146785451ee15fdf6cae371dc3005441988c7d426401San Mehat             * changed while active, we must ensure both ids are not currently mounted.
146885451ee15fdf6cae371dc3005441988c7d426401San Mehat             */
146985451ee15fdf6cae371dc3005441988c7d426401San Mehat            if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
1470a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageMounted;
1471a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1472a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1473a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1474b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
14754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        String cmd = String.format("asec rename %s %s", oldId, newId);
14764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
14774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(cmd);
14784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1479b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
148002735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1481a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
14824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
148345f61040823d8c442838f75cde8760f236603daeSan Mehat    }
148445f61040823d8c442838f75cde8760f236603daeSan Mehat
14854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String getSecureContainerPath(String id) {
14864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
1487207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1488b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1489f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
14902d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        try {
14912d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            ArrayList<String> rsp = mConnector.doCommand(String.format("asec path %s", id));
14922d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            String []tok = rsp.get(0).split(" ");
149322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            int code = Integer.parseInt(tok[0]);
14942d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            if (code != VoldResponseCode.AsecPathResult) {
14952d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat                throw new IllegalStateException(String.format("Unexpected response code %d", code));
14962d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            }
14972d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            return tok[1];
14982d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        } catch (NativeDaemonConnectorException e) {
14992d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            int code = e.getCode();
15002d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            if (code == VoldResponseCode.OpFailedStorageNotFound) {
15012d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat                throw new IllegalArgumentException(String.format("Container '%s' not found", id));
150222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            } else {
15032d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat                throw new IllegalStateException(String.format("Unexpected response code %d", code));
150422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            }
150522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
150622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
1507e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu
1508e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu    public void finishMediaUpdate() {
1509e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
1510e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu    }
151102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1512a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
1513a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        if (callerUid == android.os.Process.SYSTEM_UID) {
1514a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return true;
1515a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1516a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
151702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        if (packageName == null) {
151802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            return false;
151902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
152002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
152102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        final int packageUid = mPms.getPackageUid(packageName);
152202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
152302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        if (DEBUG_OBB) {
152402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
152502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root                    packageUid + ", callerUid = " + callerUid);
152602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
152702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
152802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        return callerUid == packageUid;
152902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
153002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
153102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    public String getMountedObbPath(String filename) {
1532af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (filename == null) {
1533af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("filename cannot be null");
1534af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        }
1535af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
153602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        waitForReady();
153702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        warnOnNotMounted();
153802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
153902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        try {
154002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            ArrayList<String> rsp = mConnector.doCommand(String.format("obb path %s", filename));
154102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            String []tok = rsp.get(0).split(" ");
154202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            int code = Integer.parseInt(tok[0]);
154302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            if (code != VoldResponseCode.AsecPathResult) {
154402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root                throw new IllegalStateException(String.format("Unexpected response code %d", code));
154502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
154602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            return tok[1];
154702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        } catch (NativeDaemonConnectorException e) {
154802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            int code = e.getCode();
154902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            if (code == VoldResponseCode.OpFailedStorageNotFound) {
1550a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                return null;
155102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            } else {
155202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root                throw new IllegalStateException(String.format("Unexpected response code %d", code));
155302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
155402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
155502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
155602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
155702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    public boolean isObbMounted(String filename) {
1558af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (filename == null) {
1559af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("filename cannot be null");
1560af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        }
1561af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1562a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        synchronized (mObbMounts) {
1563af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            return mObbPathToStateMap.containsKey(filename);
1564a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1565a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
1566a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1567af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    public void mountObb(String filename, String key, IObbActionListener token, int nonce)
1568735de3b38abbd6564082a819377673ee593744a6Kenny Root            throws RemoteException {
1569f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root        if (filename == null) {
1570f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root            throw new IllegalArgumentException("filename cannot be null");
157102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
157202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1573af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (token == null) {
1574af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("token cannot be null");
15752942391801b79816c5eb77d7ac94c4a65f26af48Kenny Root        }
1576735de3b38abbd6564082a819377673ee593744a6Kenny Root
1577af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final int callerUid = Binder.getCallingUid();
1578af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final ObbState obbState = new ObbState(filename, callerUid, token, nonce);
1579af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final ObbAction action = new MountObbAction(obbState, key);
1580a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
1581a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1582a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        if (DEBUG_OBB)
1583a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            Slog.i(TAG, "Send to OBB handler: " + action.toString());
158402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
158502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1586af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    public void unmountObb(String filename, boolean force, IObbActionListener token, int nonce)
1587af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throws RemoteException {
1588f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root        if (filename == null) {
1589f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root            throw new IllegalArgumentException("filename cannot be null");
159002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
159102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1592af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final int callerUid = Binder.getCallingUid();
1593af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final ObbState obbState = new ObbState(filename, callerUid, token, nonce);
1594af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final ObbAction action = new UnmountObbAction(obbState, force);
1595a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
1596a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1597a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        if (DEBUG_OBB)
1598a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            Slog.i(TAG, "Send to OBB handler: " + action.toString());
1599a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
160002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1601af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private void addObbStateLocked(ObbState obbState) throws RemoteException {
1602af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IBinder binder = obbState.getBinder();
1603af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        List<ObbState> obbStates = mObbMounts.get(binder);
16045919ac6b4188285324646772501ef4b97b353cf4Kenny Root
1605af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (obbStates == null) {
1606af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbStates = new ArrayList<ObbState>();
1607af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            mObbMounts.put(binder, obbStates);
1608af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        } else {
1609af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            for (final ObbState o : obbStates) {
1610af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (o.filename.equals(obbState.filename)) {
1611af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    throw new IllegalStateException("Attempt to add ObbState twice. "
1612af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            + "This indicates an error in the MountService logic.");
16135919ac6b4188285324646772501ef4b97b353cf4Kenny Root                }
16145919ac6b4188285324646772501ef4b97b353cf4Kenny Root            }
161502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
161602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1617af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        obbStates.add(obbState);
1618af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        try {
1619af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbState.link();
1620af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        } catch (RemoteException e) {
1621af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            /*
1622af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * The binder died before we could link it, so clean up our state
1623af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * and return failure.
1624af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             */
1625af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbStates.remove(obbState);
1626af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.isEmpty()) {
1627af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mObbMounts.remove(binder);
162805105f7abe02b2dff91d6260b3628c8b97816babKenny Root            }
16295919ac6b4188285324646772501ef4b97b353cf4Kenny Root
1630af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            // Rethrow the error so mountObb can get it
1631af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw e;
163202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
1633af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1634af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        mObbPathToStateMap.put(obbState.filename, obbState);
1635a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
163602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1637af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private void removeObbStateLocked(ObbState obbState) {
1638af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IBinder binder = obbState.getBinder();
1639af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final List<ObbState> obbStates = mObbMounts.get(binder);
1640af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (obbStates != null) {
1641af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.remove(obbState)) {
1642af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                obbState.unlink();
1643af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
1644af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.isEmpty()) {
1645af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mObbMounts.remove(binder);
1646af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
164738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
1648af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1649af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        mObbPathToStateMap.remove(obbState.filename);
165038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    }
165138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
1652a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private class ObbActionHandler extends Handler {
1653a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private boolean mBound = false;
1654480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root        private final List<ObbAction> mActions = new LinkedList<ObbAction>();
1655a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1656a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbActionHandler(Looper l) {
1657a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(l);
1658a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1659a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1660a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
1661a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleMessage(Message msg) {
1662a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            switch (msg.what) {
1663a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_RUN_ACTION: {
1664480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                    final ObbAction action = (ObbAction) msg.obj;
1665a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1666a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
1667a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
1668a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1669a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // If a bind was already initiated we don't really
1670a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // need to do anything. The pending install
1671a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // will be processed later on.
1672a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (!mBound) {
1673a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // If this is the only one pending we might
1674a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // have to bind to the service again.
1675a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (!connectToService()) {
1676a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            Slog.e(TAG, "Failed to bind to media container service");
1677a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.handleError();
1678a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            return;
1679a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
1680a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
1681735de3b38abbd6564082a819377673ee593744a6Kenny Root
1682735de3b38abbd6564082a819377673ee593744a6Kenny Root                    mActions.add(action);
1683a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
1684a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
1685a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_BOUND: {
1686a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
1687a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_BOUND");
1688a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (msg.obj != null) {
1689a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mContainerService = (IMediaContainerService) msg.obj;
1690a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
1691a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mContainerService == null) {
1692a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Something seriously wrong. Bail out
1693a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.e(TAG, "Cannot bind to media container service");
1694a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        for (ObbAction action : mActions) {
1695a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            // Indicate service bind error
1696a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.handleError();
1697a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
1698a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mActions.clear();
1699a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else if (mActions.size() > 0) {
1700480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                        final ObbAction action = mActions.get(0);
1701a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (action != null) {
1702a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.execute(this);
1703a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
1704a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else {
1705a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Should never happen ideally.
1706a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.w(TAG, "Empty queue");
1707a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
1708a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
1709a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
1710a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_RECONNECT: {
1711a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
1712a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_RECONNECT");
1713a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() > 0) {
1714a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (mBound) {
1715a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            disconnectService();
1716a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
1717a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (!connectToService()) {
1718a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            Slog.e(TAG, "Failed to bind to media container service");
1719a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            for (ObbAction action : mActions) {
1720a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                                // Indicate service bind error
1721a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                                action.handleError();
1722a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            }
1723a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            mActions.clear();
1724a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
1725a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
1726a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
1727a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
1728a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_UNBIND: {
1729a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
1730a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_UNBIND");
1731a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1732a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // Delete pending install
1733a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() > 0) {
1734a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mActions.remove(0);
1735a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
1736a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() == 0) {
1737a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (mBound) {
1738a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            disconnectService();
1739a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
1740a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else {
1741a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // There are more pending requests in queue.
1742a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Just post MCS_BOUND message to trigger processing
1743a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // of next pending install.
1744a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
1745a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
1746a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
1747a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
1748af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                case OBB_FLUSH_MOUNT_STATE: {
1749af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    final String path = (String) msg.obj;
1750af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1751af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    if (DEBUG_OBB)
1752af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        Slog.i(TAG, "Flushing all OBB state for path " + path);
1753af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1754af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    synchronized (mObbMounts) {
1755af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
1756af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1757af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        final Iterator<Entry<String, ObbState>> i =
1758af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                mObbPathToStateMap.entrySet().iterator();
1759af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        while (i.hasNext()) {
1760af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            final Entry<String, ObbState> obbEntry = i.next();
1761af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1762af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            /*
1763af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * If this entry's source file is in the volume path
1764af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * that got unmounted, remove it because it's no
1765af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * longer valid.
1766af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             */
1767af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            if (obbEntry.getKey().startsWith(path)) {
1768af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                obbStatesToRemove.add(obbEntry.getValue());
1769af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            }
1770af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        }
1771af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1772af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        for (final ObbState obbState : obbStatesToRemove) {
1773af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            if (DEBUG_OBB)
1774af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                Slog.i(TAG, "Removing state for " + obbState.filename);
1775af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1776af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            removeObbStateLocked(obbState);
1777af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1778af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            try {
1779af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                obbState.token.onObbResult(obbState.filename, obbState.nonce,
1780af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                        OnObbStateChangeListener.UNMOUNTED);
1781af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            } catch (RemoteException e) {
1782af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                Slog.i(TAG, "Couldn't send unmount notification for  OBB: "
1783af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                        + obbState.filename);
1784af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            }
1785af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        }
1786af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    }
1787af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    break;
1788af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                }
178902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
179002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
179102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1792a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private boolean connectToService() {
1793a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
1794a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "Trying to bind to DefaultContainerService");
1795a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1796a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
1797a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) {
1798a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mBound = true;
1799a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                return true;
180002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
1801a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return false;
1802a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1803a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1804a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private void disconnectService() {
1805a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mContainerService = null;
1806a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mBound = false;
1807a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mContext.unbindService(mDefContainerConn);
180802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
180902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
181002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1811a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    abstract class ObbAction {
1812a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private static final int MAX_RETRIES = 3;
1813a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private int mRetries;
181402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1815a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbState mObbState;
1816a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1817a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbAction(ObbState obbState) {
1818a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbState = obbState;
181902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
182002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1821a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void execute(ObbActionHandler handler) {
1822a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            try {
1823a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
1824a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.i(TAG, "Starting to execute action: " + this.toString());
1825a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mRetries++;
1826a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (mRetries > MAX_RETRIES) {
1827a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
1828480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                    mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
1829a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    handleError();
1830a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    return;
1831a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                } else {
1832a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    handleExecute();
1833a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
1834a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "Posting install MCS_UNBIND");
1835a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
1836a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
1837a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            } catch (RemoteException e) {
1838a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
1839a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.i(TAG, "Posting install MCS_RECONNECT");
1840a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
1841a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            } catch (Exception e) {
1842a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
1843a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.d(TAG, "Error handling OBB action", e);
1844a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                handleError();
184517eb6fb07cc6965f09c51adc70b3c291f57a784aKenny Root                mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
184602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
1847a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
184802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
184905105f7abe02b2dff91d6260b3628c8b97816babKenny Root        abstract void handleExecute() throws RemoteException, IOException;
1850a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        abstract void handleError();
185138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
185238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        protected ObbInfo getObbInfo() throws IOException {
185338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            ObbInfo obbInfo;
185438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            try {
185538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                obbInfo = mContainerService.getObbInfo(mObbState.filename);
185638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } catch (RemoteException e) {
185738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
185838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                        + mObbState.filename);
185938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                obbInfo = null;
186038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
186138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            if (obbInfo == null) {
186238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                throw new IOException("Couldn't read OBB file: " + mObbState.filename);
186338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
186438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return obbInfo;
186538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
186638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
1867af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        protected void sendNewStatusOrIgnore(int status) {
1868af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (mObbState == null || mObbState.token == null) {
1869af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
1870af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
1871af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
187238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            try {
1873af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mObbState.token.onObbResult(mObbState.filename, mObbState.nonce, status);
187438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } catch (RemoteException e) {
187538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
187638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
187738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
1878a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
1879a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1880a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class MountObbAction extends ObbAction {
1881a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private String mKey;
1882a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1883a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        MountObbAction(ObbState obbState, String key) {
1884a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(obbState);
1885a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mKey = key;
1886a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1887a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1888735de3b38abbd6564082a819377673ee593744a6Kenny Root        public void handleExecute() throws IOException, RemoteException {
1889af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            waitForReady();
1890af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            warnOnNotMounted();
1891af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
189238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            final ObbInfo obbInfo = getObbInfo();
189338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
1894af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mObbState.callerUid)) {
1895af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
1896af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        + " which is owned by " + obbInfo.packageName);
1897af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
1898af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
1899af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
1900af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1901af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final boolean isMounted;
1902af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            synchronized (mObbMounts) {
1903af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                isMounted = mObbPathToStateMap.containsKey(obbInfo.filename);
1904af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
1905af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (isMounted) {
1906af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
1907af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
1908af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
1909af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
1910af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
191138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            /*
1912af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * The filename passed in might not be the canonical name, so just
1913af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * set the filename to the canonicalized version.
191438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root             */
1915af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            mObbState.filename = obbInfo.filename;
191638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
1917af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final String hashedKey;
1918af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (mKey == null) {
1919af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                hashedKey = "none";
1920af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } else {
1921af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                try {
19223b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
19233b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
19243b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
19253b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                            PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
19263b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    SecretKey key = factory.generateSecret(ks);
19273b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    BigInteger bi = new BigInteger(key.getEncoded());
19283b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    hashedKey = bi.toString(16);
1929af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } catch (NoSuchAlgorithmException e) {
19303b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
19313b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
19323b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    return;
19333b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                } catch (InvalidKeySpecException e) {
19343b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
19353b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
1936af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    return;
193738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                }
1938a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
1939a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1940af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            int rc = StorageResultCode.OperationSucceeded;
1941af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            String cmd = String.format("obb mount %s %s %d", mObbState.filename, hashedKey,
1942af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    mObbState.callerUid);
1943af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            try {
1944af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mConnector.doCommand(cmd);
1945af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } catch (NativeDaemonConnectorException e) {
1946af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                int code = e.getCode();
1947af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (code != VoldResponseCode.OpFailedStorageBusy) {
1948af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedInternalError;
1949a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
1950af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
1951a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1952af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (rc == StorageResultCode.OperationSucceeded) {
1953af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (DEBUG_OBB)
1954af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    Slog.d(TAG, "Successfully mounted OBB " + mObbState.filename);
195538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
1956af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                synchronized (mObbMounts) {
1957af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    addObbStateLocked(mObbState);
1958a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
195938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
1960af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
196102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            } else {
196205105f7abe02b2dff91d6260b3628c8b97816babKenny Root                Slog.e(TAG, "Couldn't mount OBB file: " + rc);
1963a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1964af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
196502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
196602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
196702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1968a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleError() {
1969af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
197002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
1971a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1972a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
1973a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public String toString() {
1974a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            StringBuilder sb = new StringBuilder();
1975a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("MountObbAction{");
1976a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("filename=");
1977a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.filename);
1978a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",callerUid=");
1979a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.callerUid);
1980a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",token=");
1981a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.token != null ? mObbState.token.toString() : "NULL");
1982af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sb.append(",binder=");
1983af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sb.append(mObbState.token != null ? mObbState.getBinder().toString() : "null");
1984a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append('}');
1985a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return sb.toString();
1986a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1987a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
1988a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1989a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class UnmountObbAction extends ObbAction {
1990a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private boolean mForceUnmount;
1991a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1992a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        UnmountObbAction(ObbState obbState, boolean force) {
1993a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(obbState);
1994a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mForceUnmount = force;
1995a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1996a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
199738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        public void handleExecute() throws IOException {
1998af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            waitForReady();
1999af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            warnOnNotMounted();
2000af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
200138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            final ObbInfo obbInfo = getObbInfo();
2002a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2003af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final ObbState obbState;
200438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            synchronized (mObbMounts) {
2005af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                obbState = mObbPathToStateMap.get(obbInfo.filename);
2006af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
200738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2008af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbState == null) {
2009af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
2010af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2011a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
2012a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2013af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbState.callerUid != mObbState.callerUid) {
2014af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Permission denied attempting to unmount OBB " + obbInfo.filename
2015af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        + " (owned by " + obbInfo.packageName + ")");
2016af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
2017af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2018af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2019a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2020af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            mObbState.filename = obbInfo.filename;
202138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2022af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            int rc = StorageResultCode.OperationSucceeded;
2023af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            String cmd = String.format("obb unmount %s%s", mObbState.filename,
2024af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    (mForceUnmount ? " force" : ""));
2025af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            try {
2026af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mConnector.doCommand(cmd);
2027af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } catch (NativeDaemonConnectorException e) {
2028af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                int code = e.getCode();
2029af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (code == VoldResponseCode.OpFailedStorageBusy) {
2030af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedStorageBusy;
2031af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
2032af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    // If it's not mounted then we've already won.
2033af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationSucceeded;
2034af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } else {
2035af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedInternalError;
2036a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2037a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
203838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2039af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (rc == StorageResultCode.OperationSucceeded) {
2040af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                synchronized (mObbMounts) {
2041af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    removeObbStateLocked(obbState);
2042af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                }
204338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2044af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
204538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } else {
2046af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Could not mount OBB: " + mObbState.filename);
2047af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
204838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
2049a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2050a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2051a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleError() {
2052af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
2053a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2054a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2055a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
2056a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public String toString() {
2057a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            StringBuilder sb = new StringBuilder();
2058a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("UnmountObbAction{");
2059a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("filename=");
2060a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.filename != null ? mObbState.filename : "null");
2061a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",force=");
2062a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mForceUnmount);
2063a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",callerUid=");
2064a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.callerUid);
2065a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",token=");
2066a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.token != null ? mObbState.token.toString() : "null");
2067735de3b38abbd6564082a819377673ee593744a6Kenny Root            sb.append(",binder=");
2068af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sb.append(mObbState.token != null ? mObbState.getBinder().toString() : "null");
2069a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append('}');
2070a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return sb.toString();
2071a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
207202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
207338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
207438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    @Override
207538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
207638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
207738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            pw.println("Permission Denial: can't dump ActivityManager from from pid="
207838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
207938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                    + " without permission " + android.Manifest.permission.DUMP);
208038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return;
208138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
208238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
208338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        synchronized (mObbMounts) {
2084af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("  mObbMounts:");
208538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2086af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet().iterator();
2087af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            while (binders.hasNext()) {
2088af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Entry<IBinder, List<ObbState>> e = binders.next();
2089af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print("    Key="); pw.println(e.getKey().toString());
2090af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                final List<ObbState> obbStates = e.getValue();
209138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                for (final ObbState obbState : obbStates) {
2092af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    pw.print("      "); pw.println(obbState.toString());
209338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                }
209438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
2095af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2096af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("");
2097af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("  mObbPathToStateMap:");
2098af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
2099af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            while (maps.hasNext()) {
2100af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                final Entry<String, ObbState> e = maps.next();
2101af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print("    "); pw.print(e.getKey());
2102af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print(" -> "); pw.println(e.getValue().toString());
2103af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
210438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
210538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    }
21069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
21079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2108