MountService.java revision a5250c93928e256738125b265e10c96c3575597e
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;
202f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport com.android.internal.util.XmlUtils;
21c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport com.android.server.am.ActivityManagerService;
22c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
238888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parksimport android.Manifest;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
25a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ComponentName;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
29a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ServiceConnection;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
3102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.content.res.ObbInfo;
322f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.Resources;
332f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.TypedArray;
342f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.XmlResourceParser;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri;
3602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.os.Binder;
37a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.Environment;
38c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Handler;
395f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.HandlerThread;
40a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.IBinder;
415f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.Looper;
42c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Message;
432f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.os.Parcelable;
444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehatimport android.os.RemoteException;
45fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapuimport android.os.ServiceManager;
46207e538350665cea00e1aa70b8094beca4a34e45San Mehatimport android.os.SystemClock;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties;
48a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountService;
49a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountServiceListener;
50a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountShutdownObserver;
51a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IObbActionListener;
52af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Rootimport android.os.storage.OnObbStateChangeListener;
53a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.StorageResultCode;
542f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.os.storage.StorageVolume;
55f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parksimport android.text.TextUtils;
562f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.util.AttributeSet;
57a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehatimport android.util.Slog;
582f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.util.Xml;
592f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
602f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport org.xmlpull.v1.XmlPullParser;
612f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport org.xmlpull.v1.XmlPullParserException;
62a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
6338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.FileDescriptor;
6405105f7abe02b2dff91d6260b3628c8b97816babKenny Rootimport java.io.IOException;
6538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.PrintWriter;
663b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.math.BigInteger;
67735de3b38abbd6564082a819377673ee593744a6Kenny Rootimport java.security.NoSuchAlgorithmException;
683b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.InvalidKeySpecException;
693b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.KeySpec;
7022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehatimport java.util.ArrayList;
71a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.HashMap;
726cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehatimport java.util.HashSet;
7338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Iterator;
74a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.LinkedList;
75a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.List;
76a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.Map;
7738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Map.Entry;
78d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwoodimport java.util.Set;
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
803b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKey;
813b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKeyFactory;
823b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.spec.PBEKeySpec;
833b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
85b104340496e3a531e26c8f428c808eca0e039f50San Mehat * MountService implements back-end services for platform storage
86b104340496e3a531e26c8f428c808eca0e039f50San Mehat * management.
87b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @hide - Applications should use android.os.storage.StorageManager
88b104340496e3a531e26c8f428c808eca0e039f50San Mehat * to access the MountService.
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
905af0b916f850486cff4797355bf9e7dc3352fe00Jason parksclass MountService extends IMountService.Stub implements INativeDaemonConnectorCallbacks {
915af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
92b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private static final boolean LOCAL_LOGD = false;
938a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu    private static final boolean DEBUG_UNMOUNT = false;
948a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu    private static final boolean DEBUG_EVENTS = false;
95b7db2726e91f1d9480359d0f83b9cb7769906b34Kenny Root    private static final boolean DEBUG_OBB = false;
9602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "MountService";
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
99305bcbf0c961840c4505770d084a1caacc074dbbKenny Root    private static final String VOLD_TAG = "VoldConnector";
100305bcbf0c961840c4505770d084a1caacc074dbbKenny Root
1014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    /*
1024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Internal vold volume state constants
1034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     */
1047fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    class VolumeState {
1057fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Init       = -1;
1067fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int NoMedia    = 0;
1077fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Idle       = 1;
1087fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Pending    = 2;
1097fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Checking   = 3;
1107fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Mounted    = 4;
1117fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Unmounting = 5;
1127fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Formatting = 6;
1137fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Shared     = 7;
1147fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int SharedMnt  = 8;
1157fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
1167fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
1174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    /*
1184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Internal vold response code constants
1194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     */
12022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    class VoldResponseCode {
1214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 100 series - Requestion action was initiated; expect another reply
1234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         *              before proceeding with a new command.
1244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
12522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeListResult               = 110;
12622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int AsecListResult                 = 111;
127c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        public static final int StorageUsersListResult         = 112;
12822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
1294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 200 series - Requestion action has been successfully completed.
1314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
1324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int ShareStatusResult              = 210;
13322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int AsecPathResult                 = 211;
1344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int ShareEnabledResult             = 212;
13522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
1364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 400 series - Command was accepted, but the requested action
1384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         *              did not take place.
1394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
1404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedNoMedia                = 401;
1414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedMediaBlank             = 402;
1424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedMediaCorrupt           = 403;
1434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedVolNotMounted          = 404;
144d970998b0d489774ad1c5b94b47d233912f00214San Mehat        public static final int OpFailedStorageBusy            = 405;
1452d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        public static final int OpFailedStorageNotFound        = 406;
1464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 600 series - Unsolicited broadcasts.
1494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
15022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeStateChange              = 605;
15122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int ShareAvailabilityChange        = 620;
15222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeDiskInserted             = 630;
15322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeDiskRemoved              = 631;
15422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeBadRemoval               = 632;
15522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
15622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
1574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private Context                               mContext;
1584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private NativeDaemonConnector                 mConnector;
1592f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    private final ArrayList<StorageVolume>        mVolumes = new ArrayList<StorageVolume>();
1602f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    private StorageVolume                         mPrimaryVolume;
161f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood    private final HashMap<String, String>         mVolumeStates = new HashMap<String, String>();
162a5250c93928e256738125b265e10c96c3575597eMike Lockwood    private final HashMap<String, StorageVolume>  mVolumeMap = new HashMap<String, StorageVolume>();
163f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood    private String                                mExternalStoragePath;
1644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private PackageManagerService                 mPms;
1654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private boolean                               mUmsEnabling;
1660eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    // Used as a lock for methods that register/unregister listeners.
1670eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    final private ArrayList<MountServiceBinderListener> mListeners =
1680eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            new ArrayList<MountServiceBinderListener>();
1696a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private boolean                               mBooted = false;
1706a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private boolean                               mReady = false;
1716a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private boolean                               mSendUmsConnectedOnBoot = false;
17203559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood    // true if we should fake MEDIA_MOUNTED state for external storage
17303559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood    private boolean                               mEmulateExternalStorage = false;
174fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapu
1756cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    /**
1766cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat     * Private hash of currently mounted secure containers.
1770eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu     * Used as a lock in methods to manipulate secure containers.
1786cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat     */
1790eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    final private HashSet<String> mAsecMountSet = new HashSet<String>();
1806cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
18102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    /**
1823b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * The size of the crypto algorithm key in bits for OBB files. Currently
1833b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * Twofish is used which takes 128-bit keys.
1843b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     */
1853b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
1863b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
1873b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    /**
1883b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * The number of times to run SHA1 in the PBKDF2 function for OBB files.
1893b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * 1024 is reasonably secure and not too slow.
1903b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     */
1913b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    private static final int PBKDF2_HASH_ROUNDS = 1024;
1923b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
1933b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    /**
194a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * Mounted OBB tracking information. Used to track the current state of all
195a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * OBBs.
196a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     */
197735de3b38abbd6564082a819377673ee593744a6Kenny Root    final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
198a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
199a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
200a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class ObbState implements IBinder.DeathRecipient {
201af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        public ObbState(String filename, int callerUid, IObbActionListener token, int nonce)
202735de3b38abbd6564082a819377673ee593744a6Kenny Root                throws RemoteException {
203a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            this.filename = filename;
204a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            this.callerUid = callerUid;
205af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            this.token = token;
206af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            this.nonce = nonce;
207a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
208a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
209a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        // OBB source filename
210af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        String filename;
211a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
212a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        // Binder.callingUid()
21305105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final public int callerUid;
214a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
215af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        // Token of remote Binder caller
216af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IObbActionListener token;
217af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
218af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        // Identifier to pass back to the token
219af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final int nonce;
220a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
221735de3b38abbd6564082a819377673ee593744a6Kenny Root        public IBinder getBinder() {
222735de3b38abbd6564082a819377673ee593744a6Kenny Root            return token.asBinder();
223735de3b38abbd6564082a819377673ee593744a6Kenny Root        }
224735de3b38abbd6564082a819377673ee593744a6Kenny Root
225a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
226a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void binderDied() {
227a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            ObbAction action = new UnmountObbAction(this, true);
228a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
229735de3b38abbd6564082a819377673ee593744a6Kenny Root        }
230a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2315919ac6b4188285324646772501ef4b97b353cf4Kenny Root        public void link() throws RemoteException {
2325919ac6b4188285324646772501ef4b97b353cf4Kenny Root            getBinder().linkToDeath(this, 0);
2335919ac6b4188285324646772501ef4b97b353cf4Kenny Root        }
2345919ac6b4188285324646772501ef4b97b353cf4Kenny Root
2355919ac6b4188285324646772501ef4b97b353cf4Kenny Root        public void unlink() {
236735de3b38abbd6564082a819377673ee593744a6Kenny Root            getBinder().unlinkToDeath(this, 0);
237a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
23838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
23938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        @Override
24038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        public String toString() {
24138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            StringBuilder sb = new StringBuilder("ObbState{");
24238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append("filename=");
24338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(filename);
24438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(",token=");
24538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(token.toString());
24638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(",callerUid=");
24738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(callerUid);
24838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append('}');
24938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return sb.toString();
25038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
251a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
252a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
253a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // OBB Action Handler
254a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private ObbActionHandler mObbActionHandler;
255a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
256a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // OBB action handler messages
257a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_RUN_ACTION = 1;
258a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_BOUND = 2;
259a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_UNBIND = 3;
260a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_RECONNECT = 4;
261af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private static final int OBB_FLUSH_MOUNT_STATE = 5;
262a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
263a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    /*
264a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * Default Container Service information
26502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root     */
266a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
267a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
268a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
269a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
270a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
271a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class DefaultContainerConnection implements ServiceConnection {
272a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void onServiceConnected(ComponentName name, IBinder service) {
273a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
274a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "onServiceConnected");
275a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
276a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
277a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
278a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
279a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void onServiceDisconnected(ComponentName name) {
280a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
281a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "onServiceDisconnected");
282a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
283a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    };
284a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
285a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // Used in the ObbActionHandler
286a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private IMediaContainerService mContainerService = null;
28702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
28802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    // Handler messages
289c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_PM_UPDATE = 1;
290c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_PM_DONE = 2;
291c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_MS = 3;
292c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int RETRY_UNMOUNT_DELAY = 30; // in ms
293c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int MAX_UNMOUNT_RETRIES = 4;
294c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
295c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    class UnmountCallBack {
29605105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final String path;
29705105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final boolean force;
298c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        int retries;
299c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
300c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        UnmountCallBack(String path, boolean force) {
301c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            retries = 0;
302c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            this.path = path;
303c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            this.force = force;
304c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        }
3050eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3060eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        void handleFinished() {
307a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path);
3080eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            doUnmountVolume(path, true);
3090eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
3100eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
3110eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3120eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    class UmsEnableCallBack extends UnmountCallBack {
31305105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final String method;
3140eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3150eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        UmsEnableCallBack(String path, String method, boolean force) {
3160eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            super(path, force);
3170eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            this.method = method;
3180eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
3190eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3200eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        @Override
3210eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        void handleFinished() {
3220eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            super.handleFinished();
3230eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            doShareUnshareVolume(path, method, true);
3240eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
325c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    }
326c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
3276ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    class ShutdownCallBack extends UnmountCallBack {
3286ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        IMountShutdownObserver observer;
3296ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        ShutdownCallBack(String path, IMountShutdownObserver observer) {
3306ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            super(path, true);
3316ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            this.observer = observer;
3326ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        }
3336ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3346ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        @Override
3356ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        void handleFinished() {
3366ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            int ret = doUnmountVolume(path, true);
3376ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            if (observer != null) {
3386ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                try {
3396ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    observer.onShutDownComplete(ret);
3406ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                } catch (RemoteException e) {
341a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.w(TAG, "RemoteException when shutting down");
3426ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                }
3436ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            }
3446ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        }
3456ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    }
3466ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3475f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler    class MountServiceHandler extends Handler {
348c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>();
349e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        boolean mUpdatingStatus = false;
3506ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3515f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        MountServiceHandler(Looper l) {
3525f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler            super(l);
3535f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        }
3545f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler
3555af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
356c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        public void handleMessage(Message msg) {
357c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            switch (msg.what) {
358c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                case H_UNMOUNT_PM_UPDATE: {
359a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_UPDATE");
360c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    UnmountCallBack ucb = (UnmountCallBack) msg.obj;
361c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    mForceUnmounts.add(ucb);
362a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, " registered = " + mUpdatingStatus);
3636ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    // Register only if needed.
364e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                    if (!mUpdatingStatus) {
365a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        if (DEBUG_UNMOUNT) Slog.i(TAG, "Updating external media status on PackageManager");
366e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                        mUpdatingStatus = true;
367e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                        mPms.updateExternalMediaStatus(false, true);
368c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    }
369c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
370c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
371c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                case H_UNMOUNT_PM_DONE: {
372a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_DONE");
373a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "Updated status. Processing requests");
374e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                    mUpdatingStatus = false;
3756ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int size = mForceUnmounts.size();
3766ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int sizeArr[] = new int[size];
3776ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int sizeArrN = 0;
3787af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    // Kill processes holding references first
3797af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    ActivityManagerService ams = (ActivityManagerService)
3807af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    ServiceManager.getService("activity");
3816ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    for (int i = 0; i < size; i++) {
3826ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        UnmountCallBack ucb = mForceUnmounts.get(i);
3836ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        String path = ucb.path;
3846ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        boolean done = false;
3856ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        if (!ucb.force) {
386c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                            done = true;
387c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        } else {
3886ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            int pids[] = getStorageUsers(path);
3896ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            if (pids == null || pids.length == 0) {
3906ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                                done = true;
3916ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            } else {
3926ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                                // Eliminate system process here?
393648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn                                ams.killPids(pids, "unmount media", true);
3947af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                // Confirm if file references have been freed.
3957af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                pids = getStorageUsers(path);
3967af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                if (pids == null || pids.length == 0) {
3977af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    done = true;
398c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                                }
399c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                            }
400c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        }
4017af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                        if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) {
4027af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            // Retry again
4037af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            Slog.i(TAG, "Retrying to kill storage users again");
4047af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            mHandler.sendMessageDelayed(
4057af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    mHandler.obtainMessage(H_UNMOUNT_PM_DONE,
4067af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                            ucb.retries++),
4077af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    RETRY_UNMOUNT_DELAY);
408c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        } else {
4096ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            if (ucb.retries >= MAX_UNMOUNT_RETRIES) {
4107af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                Slog.i(TAG, "Failed to unmount media inspite of " +
4117af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                        MAX_UNMOUNT_RETRIES + " retries. Forcibly killing processes now");
4126ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            }
4137af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            sizeArr[sizeArrN++] = i;
4147af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS,
4157af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    ucb));
416c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        }
417c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    }
4186ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    // Remove already processed elements from list.
4196ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    for (int i = (sizeArrN-1); i >= 0; i--) {
4206ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        mForceUnmounts.remove(sizeArr[i]);
4216ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    }
422c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
423c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
424c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                case H_UNMOUNT_MS : {
425a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_MS");
426c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    UnmountCallBack ucb = (UnmountCallBack) msg.obj;
4270eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                    ucb.handleFinished();
428c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
429c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
430c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            }
431c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        }
432c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    };
4335f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler    final private HandlerThread mHandlerThread;
4345f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler    final private Handler mHandler;
435c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
436207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void waitForReady() {
437207e538350665cea00e1aa70b8094beca4a34e45San Mehat        while (mReady == false) {
438207e538350665cea00e1aa70b8094beca4a34e45San Mehat            for (int retries = 5; retries > 0; retries--) {
439207e538350665cea00e1aa70b8094beca4a34e45San Mehat                if (mReady) {
440207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    return;
441207e538350665cea00e1aa70b8094beca4a34e45San Mehat                }
442207e538350665cea00e1aa70b8094beca4a34e45San Mehat                SystemClock.sleep(1000);
443207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
444a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.w(TAG, "Waiting too long for mReady!");
445207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
4461f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat    }
44702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
448207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
4495af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
45191c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat            String action = intent.getAction();
45291c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
45391c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat            if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
454207e538350665cea00e1aa70b8094beca4a34e45San Mehat                mBooted = true;
45522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
456c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                /*
457c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                 * In the simulator, we need to broadcast a volume mounted event
458c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                 * to make the media scanner run.
459c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                 */
460c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
461b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                    notifyVolumeStateChange(null, "/sdcard", VolumeState.NoMedia,
462b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                            VolumeState.Mounted);
463c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                    return;
464c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                }
465fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                new Thread() {
4665af0b916f850486cff4797355bf9e7dc3352fe00Jason parks                    @Override
467fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                    public void run() {
468fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                        try {
469b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                            // it is not safe to call vold with mVolumeStates locked
470b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                            // so we make a copy of the paths and states and process them
471b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                            // outside the lock
472b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                            String[] paths, states;
473b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                            int count;
474f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                            synchronized (mVolumeStates) {
475b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                Set<String> keys = mVolumeStates.keySet();
476b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                count = keys.size();
477b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                paths = (String[])keys.toArray(new String[count]);
478b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                states = new String[count];
479b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                for (int i = 0; i < count; i++) {
480b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                    states[i] = mVolumeStates.get(paths[i]);
481b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                }
482b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                            }
483b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood
484b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                            for (int i = 0; i < count; i++) {
485b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                String path = paths[i];
486b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                String state = states[i];
487b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood
488b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                if (state.equals(Environment.MEDIA_UNMOUNTED)) {
489b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                    int rc = doMountVolume(path);
490b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                    if (rc != StorageResultCode.OperationSucceeded) {
491b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                        Slog.e(TAG, String.format("Boot-time mount failed (%d)",
492b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                                rc));
493f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                                    }
494b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                } else if (state.equals(Environment.MEDIA_SHARED)) {
495b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                    /*
496b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                     * Bootstrap UMS enabled state since vold indicates
497b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                     * the volume is shared (runtime restart while ums enabled)
498b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                     */
499b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                    notifyVolumeStateChange(null, path, VolumeState.NoMedia,
500b9135638c5b813e876dc16dcb10084b6ab3d2003Mike Lockwood                                            VolumeState.Shared);
501fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                                }
502fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                            }
5036a254403235196692b1769d2fe281b0852c0cc25San Mehat
50491dd02c3405a76e9051f7e118ad19ca111b2aa40Mike Lockwood                            /* notify external storage has mounted to trigger media scanner */
50591dd02c3405a76e9051f7e118ad19ca111b2aa40Mike Lockwood                            if (mEmulateExternalStorage) {
50691dd02c3405a76e9051f7e118ad19ca111b2aa40Mike Lockwood                                notifyVolumeStateChange(null,
50791dd02c3405a76e9051f7e118ad19ca111b2aa40Mike Lockwood                                        Environment.getExternalStorageDirectory().getPath(),
50891dd02c3405a76e9051f7e118ad19ca111b2aa40Mike Lockwood                                        VolumeState.NoMedia, VolumeState.Mounted);
50991dd02c3405a76e9051f7e118ad19ca111b2aa40Mike Lockwood                            }
51091dd02c3405a76e9051f7e118ad19ca111b2aa40Mike Lockwood
5116a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                            /*
5126a254403235196692b1769d2fe281b0852c0cc25San Mehat                             * If UMS was connected on boot, send the connected event
5136a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                             * now that we're up.
5146a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                             */
5156a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                            if (mSendUmsConnectedOnBoot) {
5166a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                                sendUmsIntent(true);
5176a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                                mSendUmsConnectedOnBoot = false;
5186a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                            }
519fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                        } catch (Exception ex) {
520a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.e(TAG, "Boot-time mount exception", ex);
521fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                        }
522207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    }
523fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                }.start();
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private final class MountServiceBinderListener implements IBinder.DeathRecipient {
5294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        final IMountServiceListener mListener;
53091c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
5314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        MountServiceBinderListener(IMountServiceListener listener) {
5324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mListener = listener;
53302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
53491c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat        }
53591c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
5364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public void binderDied() {
537a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!");
538a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            synchronized (mListeners) {
5394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListeners.remove(this);
5404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListener.asBinder().unlinkToDeath(this, 0);
54191c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat            }
54291c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat        }
54391c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat    }
54491c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
5450eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private void doShareUnshareVolume(String path, String method, boolean enable) {
5464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        // TODO: Add support for multiple share methods
5474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (!method.equals("ums")) {
5484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            throw new IllegalArgumentException(String.format("Method %s not supported", method));
5497fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
5524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(String.format(
5534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    "volume %sshare %s %s", (enable ? "" : "un"), path, method));
5544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
555a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Failed to share/unshare", e);
55622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
559207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void updatePublicVolumeState(String path, String state) {
560f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood        String oldState;
561f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood        synchronized(mVolumeStates) {
562f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            oldState = mVolumeStates.put(path, state);
5637fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
564f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood        if (state.equals(oldState)) {
565f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            Slog.w(TAG, String.format("Duplicate state transition (%s -> %s) for %s",
566f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    state, state, path));
567b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return;
568b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
569af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
570f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood        Slog.d(TAG, "volume state changed for " + path + " (" + oldState + " -> " + state + ")");
571f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood
572f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood        if (path.equals(mExternalStoragePath)) {
573f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            // Update state on PackageManager, but only of real events
574f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            if (!mEmulateExternalStorage) {
575f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                if (Environment.MEDIA_UNMOUNTED.equals(state)) {
576f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    mPms.updateExternalMediaStatus(false, false);
577f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood
578f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    /*
579f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * Some OBBs might have been unmounted when this volume was
580f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * unmounted, so send a message to the handler to let it know to
581f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * remove those from the list of mounted OBBS.
582f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     */
583f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
584f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                            OBB_FLUSH_MOUNT_STATE, path));
585f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                } else if (Environment.MEDIA_MOUNTED.equals(state)) {
586f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    mPms.updateExternalMediaStatus(true, false);
587f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                }
58803559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood            }
5898a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
5904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
5914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for (int i = mListeners.size() -1; i >= 0; i--) {
5924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                MountServiceBinderListener bl = mListeners.get(i);
5934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                try {
594b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    bl.mListener.onStorageStateChanged(path, oldState, state);
5954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (RemoteException rex) {
596a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener dead");
5974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(i);
5984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (Exception ex) {
599a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener failed", ex);
6004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
60522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    /**
60622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     *
60722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     * Callback from NativeDaemonConnector
60822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     */
60922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    public void onDaemonConnected() {
6105b77dab23469273d41f9c530d947ac055765e6eaSan Mehat        /*
6115b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         * Since we'll be calling back into the NativeDaemonConnector,
6125b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         * we need to do our work in a new thread.
6135b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         */
6147fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        new Thread() {
6155af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            @Override
6167fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            public void run() {
6175b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                /**
6185b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                 * Determine media state and UMS detection status
6195b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                 */
6207fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                try {
6215b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                    String[] vols = mConnector.doListCommand(
6224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        "volume list", VoldResponseCode.VolumeListResult);
6235b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                    for (String volstr : vols) {
6245b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        String[] tok = volstr.split(" ");
6255b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        // FMT: <label> <mountpoint> <state>
626f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        String path = tok[1];
627f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        String state = Environment.MEDIA_REMOVED;
628f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood
6295b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        int st = Integer.parseInt(tok[2]);
6305b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        if (st == VolumeState.NoMedia) {
6315b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_REMOVED;
6325b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Idle) {
633207e538350665cea00e1aa70b8094beca4a34e45San Mehat                            state = Environment.MEDIA_UNMOUNTED;
6345b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Mounted) {
6355b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_MOUNTED;
636a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.i(TAG, "Media already mounted on daemon connection");
6375b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Shared) {
6385b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_SHARED;
639a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.i(TAG, "Media shared on daemon connection");
6405b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else {
6415b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            throw new Exception(String.format("Unexpected state %d", st));
6427fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                        }
643f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood
644f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        if (state != null) {
645f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                            if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state);
646f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                            updatePublicVolumeState(path, state);
647f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        }
648c2a39471642e31d7350910612e40d078b825173aSan Mehat                    }
6495b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                } catch (Exception e) {
650a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Error processing initial volume state", e);
651f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    updatePublicVolumeState(mExternalStoragePath, Environment.MEDIA_REMOVED);
6527fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                }
6537fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
6547fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                try {
655207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    boolean avail = doGetShareMethodAvailable("ums");
6567fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                    notifyShareAvailabilityChange("ums", avail);
6577fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                } catch (Exception ex) {
658a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.w(TAG, "Failed to get share availability");
6597fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                }
660207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
6619ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                 * Now that we've done our initialization, release
662207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * the hounds!
663207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
664207e538350665cea00e1aa70b8094beca4a34e45San Mehat                mReady = true;
6657fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            }
6667fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }.start();
6677fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
6687fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
66922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    /**
67022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     * Callback from NativeDaemonConnector
67122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     */
67222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    public boolean onEvent(int code, String raw, String[] cooked) {
6738a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        if (DEBUG_EVENTS) {
6748a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            StringBuilder builder = new StringBuilder();
6758a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            builder.append("onEvent::");
6768a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            builder.append(" raw= " + raw);
6778a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            if (cooked != null) {
6788a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                builder.append(" cooked = " );
6798a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                for (String str : cooked) {
6808a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                    builder.append(" " + str);
6818a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                }
6828a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            }
683a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.i(TAG, builder.toString());
6848a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
68522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        if (code == VoldResponseCode.VolumeStateChange) {
6864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            /*
6874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * One of the volumes we're managing has changed state.
6884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * Format: "NNN Volume <label> <path> state changed
6894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * from <old_#> (<old_str>) to <new_#> (<new_str>)"
6904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             */
69122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            notifyVolumeStateChange(
69222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat                    cooked[2], cooked[3], Integer.parseInt(cooked[7]),
69322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat                            Integer.parseInt(cooked[10]));
69422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        } else if (code == VoldResponseCode.ShareAvailabilityChange) {
69522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Share method <method> now <available|unavailable>
69622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            boolean avail = false;
69722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            if (cooked[5].equals("available")) {
69822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat                avail = true;
69922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            }
70022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            notifyShareAvailabilityChange(cooked[3], avail);
7014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } else if ((code == VoldResponseCode.VolumeDiskInserted) ||
7024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                   (code == VoldResponseCode.VolumeDiskRemoved) ||
7034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                   (code == VoldResponseCode.VolumeBadRemoval)) {
70422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
70522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
70622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
707a5250c93928e256738125b265e10c96c3575597eMike Lockwood            String action = null;
7084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            final String label = cooked[2];
7094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            final String path = cooked[3];
7104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            int major = -1;
7114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            int minor = -1;
7124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
7134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            try {
7144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                String devComp = cooked[6].substring(1, cooked[6].length() -1);
7154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                String[] devTok = devComp.split(":");
7164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                major = Integer.parseInt(devTok[0]);
7174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                minor = Integer.parseInt(devTok[1]);
7184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } catch (Exception ex) {
719a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to parse major/minor", ex);
7204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
7214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
7224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            if (code == VoldResponseCode.VolumeDiskInserted) {
7234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                new Thread() {
7245af0b916f850486cff4797355bf9e7dc3352fe00Jason parks                    @Override
7254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    public void run() {
7264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        try {
7274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                            int rc;
728b104340496e3a531e26c8f428c808eca0e039f50San Mehat                            if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
729a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                                Slog.w(TAG, String.format("Insertion mount failed (%d)", rc));
7304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                            }
7314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        } catch (Exception ex) {
732a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.w(TAG, "Failed to mount media on insertion", ex);
7334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        }
7344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    }
7354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }.start();
7364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else if (code == VoldResponseCode.VolumeDiskRemoved) {
7374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /*
7384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                 * This event gets trumped if we're already in BAD_REMOVAL state
7394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                 */
7404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
7414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    return true;
7424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
7434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /* Send the media unmounted event first */
744a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
7454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
746a5250c93928e256738125b265e10c96c3575597eMike Lockwood                sendStorageIntent(Environment.MEDIA_UNMOUNTED, path);
7474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
748a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed");
7494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
750a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_REMOVED;
7514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else if (code == VoldResponseCode.VolumeBadRemoval) {
752a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
7534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /* Send the media unmounted event first */
7544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
755a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_UNMOUNTED;
7564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
757a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal");
7584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);
759a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_BAD_REMOVAL;
7604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else {
761a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Unknown code {%d}", code));
7624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
763a5250c93928e256738125b265e10c96c3575597eMike Lockwood
764a5250c93928e256738125b265e10c96c3575597eMike Lockwood            if (action != null) {
765a5250c93928e256738125b265e10c96c3575597eMike Lockwood                sendStorageIntent(action, path);
766a5250c93928e256738125b265e10c96c3575597eMike Lockwood            }
76722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        } else {
76822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            return false;
76922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
7704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
7715f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        return true;
77222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
77322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
774207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void notifyVolumeStateChange(String label, String path, int oldState, int newState) {
7754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        String vs = getVolumeState(path);
776a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChanged::" + vs);
7774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
778a5250c93928e256738125b265e10c96c3575597eMike Lockwood        String action = null;
7797fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
780bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood        if (oldState == VolumeState.Shared && newState != oldState) {
781a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent");
782a5250c93928e256738125b265e10c96c3575597eMike Lockwood            sendStorageIntent(Intent.ACTION_MEDIA_UNSHARED,  path);
783bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood        }
784bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood
7857fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        if (newState == VolumeState.Init) {
7867fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.NoMedia) {
7877fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            // NoMedia is handled via Disk Remove events
7887fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Idle) {
7895fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat            /*
7905fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or
7915fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             * if we're in the process of enabling UMS
7925fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             */
7934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            if (!vs.equals(
7944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    Environment.MEDIA_BAD_REMOVAL) && !vs.equals(
7954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                            Environment.MEDIA_NOFS) && !vs.equals(
7960eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                                    Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) {
797a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable");
7984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
799a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_UNMOUNTED;
8007fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            }
8017fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Pending) {
8027fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Checking) {
803a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking");
8044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            updatePublicVolumeState(path, Environment.MEDIA_CHECKING);
805a5250c93928e256738125b265e10c96c3575597eMike Lockwood            action = Intent.ACTION_MEDIA_CHECKING;
8067fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Mounted) {
807a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted");
8084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            updatePublicVolumeState(path, Environment.MEDIA_MOUNTED);
809a5250c93928e256738125b265e10c96c3575597eMike Lockwood            action = Intent.ACTION_MEDIA_MOUNTED;
8107fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Unmounting) {
811a5250c93928e256738125b265e10c96c3575597eMike Lockwood            action = Intent.ACTION_MEDIA_EJECT;
8127fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Formatting) {
8137fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Shared) {
814a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted");
8154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            /* Send the media unmounted event first */
8164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
817a5250c93928e256738125b265e10c96c3575597eMike Lockwood            sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, path);
8184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
819a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared");
8204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            updatePublicVolumeState(path, Environment.MEDIA_SHARED);
821a5250c93928e256738125b265e10c96c3575597eMike Lockwood            action = Intent.ACTION_MEDIA_SHARED;
822a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent");
8237fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.SharedMnt) {
824a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Live shared mounts not supported yet!");
8254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            return;
8267fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else {
827a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Unhandled VolumeState {" + newState + "}");
8287fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
8297fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
830a5250c93928e256738125b265e10c96c3575597eMike Lockwood        if (action != null) {
831a5250c93928e256738125b265e10c96c3575597eMike Lockwood            sendStorageIntent(action, path);
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
835207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private boolean doGetShareMethodAvailable(String method) {
83685fb20665feadda526ad422c093b859e8c4d40bcKenny Root        ArrayList<String> rsp;
837a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
83885fb20665feadda526ad422c093b859e8c4d40bcKenny Root            rsp = mConnector.doCommand("share status " + method);
839a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException ex) {
840a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            Slog.e(TAG, "Failed to determine whether share method " + method + " is available.");
841a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            return false;
842a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
843207e538350665cea00e1aa70b8094beca4a34e45San Mehat
844207e538350665cea00e1aa70b8094beca4a34e45San Mehat        for (String line : rsp) {
845a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            String[] tok = line.split(" ");
846a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            if (tok.length < 3) {
847a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                Slog.e(TAG, "Malformed response to share status " + method);
848a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                return false;
849a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            }
850a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root
851207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code;
852207e538350665cea00e1aa70b8094beca4a34e45San Mehat            try {
853207e538350665cea00e1aa70b8094beca4a34e45San Mehat                code = Integer.parseInt(tok[0]);
854207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } catch (NumberFormatException nfe) {
855a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
856207e538350665cea00e1aa70b8094beca4a34e45San Mehat                return false;
857207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
858207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.ShareStatusResult) {
859207e538350665cea00e1aa70b8094beca4a34e45San Mehat                if (tok[2].equals("available"))
860207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    return true;
861207e538350665cea00e1aa70b8094beca4a34e45San Mehat                return false;
862207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
863a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Unexpected response code %d", code));
864207e538350665cea00e1aa70b8094beca4a34e45San Mehat                return false;
865207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
866207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
867a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        Slog.e(TAG, "Got an empty response");
868207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return false;
869207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
870207e538350665cea00e1aa70b8094beca4a34e45San Mehat
871207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private int doMountVolume(String path) {
872b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
873207e538350665cea00e1aa70b8094beca4a34e45San Mehat
874a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path);
875207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
876207e538350665cea00e1aa70b8094beca4a34e45San Mehat            mConnector.doCommand(String.format("volume mount %s", path));
877207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
878207e538350665cea00e1aa70b8094beca4a34e45San Mehat            /*
879207e538350665cea00e1aa70b8094beca4a34e45San Mehat             * Mount failed for some reason
880207e538350665cea00e1aa70b8094beca4a34e45San Mehat             */
881a5250c93928e256738125b265e10c96c3575597eMike Lockwood            String action = null;
882207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
883207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedNoMedia) {
884207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
885207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Attempt to mount but no media inserted
886207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
887b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedNoMedia;
888207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaBlank) {
889a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs");
890207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
891207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Media is blank or does not contain a supported filesystem
892207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
893207e538350665cea00e1aa70b8094beca4a34e45San Mehat                updatePublicVolumeState(path, Environment.MEDIA_NOFS);
894a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_NOFS;
895b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedMediaBlank;
896207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
897a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state media corrupt");
898207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
899207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Volume consistency check failed
900207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
901207e538350665cea00e1aa70b8094beca4a34e45San Mehat                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
902a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_UNMOUNTABLE;
903b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedMediaCorrupt;
904207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
905b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedInternalError;
906207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
907207e538350665cea00e1aa70b8094beca4a34e45San Mehat
908207e538350665cea00e1aa70b8094beca4a34e45San Mehat            /*
909207e538350665cea00e1aa70b8094beca4a34e45San Mehat             * Send broadcast intent (if required for the failure)
910207e538350665cea00e1aa70b8094beca4a34e45San Mehat             */
911a5250c93928e256738125b265e10c96c3575597eMike Lockwood            if (action != null) {
912a5250c93928e256738125b265e10c96c3575597eMike Lockwood                sendStorageIntent(action, path);
913207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
914207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
915207e538350665cea00e1aa70b8094beca4a34e45San Mehat
916207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return rc;
917207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
918207e538350665cea00e1aa70b8094beca4a34e45San Mehat
919c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    /*
920c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * If force is not set, we do not unmount if there are
921c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * processes holding references to the volume about to be unmounted.
922c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * If force is set, all the processes holding references need to be
923c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * killed via the ActivityManager before actually unmounting the volume.
924c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * This might even take a while and might be retried after timed delays
925c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * to make sure we dont end up in an instable state and kill some core
926c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * processes.
927c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     */
928d970998b0d489774ad1c5b94b47d233912f00214San Mehat    private int doUnmountVolume(String path, boolean force) {
92959443a673a736978361dc341f41ce4e9dae053a0San Mehat        if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
930207e538350665cea00e1aa70b8094beca4a34e45San Mehat            return VoldResponseCode.OpFailedVolNotMounted;
931207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
932aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
933aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
934aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
935aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
936aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
937aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
938aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
939aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
940aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
941c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        // Redundant probably. But no harm in updating state again.
942e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        mPms.updateExternalMediaStatus(false, false);
943207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
944d970998b0d489774ad1c5b94b47d233912f00214San Mehat            mConnector.doCommand(String.format(
945d970998b0d489774ad1c5b94b47d233912f00214San Mehat                    "volume unmount %s%s", path, (force ? " force" : "")));
946e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            // We unmounted the volume. None of the asec containers are available now.
947e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            synchronized (mAsecMountSet) {
948e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                mAsecMountSet.clear();
949e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            }
950b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return StorageResultCode.OperationSucceeded;
951207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
952207e538350665cea00e1aa70b8094beca4a34e45San Mehat            // Don't worry about mismatch in PackageManager since the
953207e538350665cea00e1aa70b8094beca4a34e45San Mehat            // call back will handle the status changes any way.
954207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
955207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedVolNotMounted) {
956a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageNotMounted;
957d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else if (code == VoldResponseCode.OpFailedStorageBusy) {
958d970998b0d489774ad1c5b94b47d233912f00214San Mehat                return StorageResultCode.OperationFailedStorageBusy;
959207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
960b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedInternalError;
961207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
962207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
963207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
964207e538350665cea00e1aa70b8094beca4a34e45San Mehat
965207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private int doFormatVolume(String path) {
966207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
967207e538350665cea00e1aa70b8094beca4a34e45San Mehat            String cmd = String.format("volume format %s", path);
968207e538350665cea00e1aa70b8094beca4a34e45San Mehat            mConnector.doCommand(cmd);
969b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return StorageResultCode.OperationSucceeded;
970207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
971207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
972207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedNoMedia) {
973b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedNoMedia;
974207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
975b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedMediaCorrupt;
976207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
977b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedInternalError;
978207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
979207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
980207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
981207e538350665cea00e1aa70b8094beca4a34e45San Mehat
982b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private boolean doGetVolumeShared(String path, String method) {
983b104340496e3a531e26c8f428c808eca0e039f50San Mehat        String cmd = String.format("volume shared %s %s", path, method);
984a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        ArrayList<String> rsp;
985a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root
986a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
987a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            rsp = mConnector.doCommand(cmd);
988a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException ex) {
989a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            Slog.e(TAG, "Failed to read response to volume shared " + path + " " + method);
990a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            return false;
991a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
992b104340496e3a531e26c8f428c808eca0e039f50San Mehat
993b104340496e3a531e26c8f428c808eca0e039f50San Mehat        for (String line : rsp) {
994a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            String[] tok = line.split(" ");
995a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            if (tok.length < 3) {
996a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                Slog.e(TAG, "Malformed response to volume shared " + path + " " + method + " command");
997a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                return false;
998a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            }
999a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root
1000b104340496e3a531e26c8f428c808eca0e039f50San Mehat            int code;
1001b104340496e3a531e26c8f428c808eca0e039f50San Mehat            try {
1002b104340496e3a531e26c8f428c808eca0e039f50San Mehat                code = Integer.parseInt(tok[0]);
1003b104340496e3a531e26c8f428c808eca0e039f50San Mehat            } catch (NumberFormatException nfe) {
1004a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
1005b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return false;
1006b104340496e3a531e26c8f428c808eca0e039f50San Mehat            }
1007b104340496e3a531e26c8f428c808eca0e039f50San Mehat            if (code == VoldResponseCode.ShareEnabledResult) {
1008a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                return "enabled".equals(tok[2]);
1009b104340496e3a531e26c8f428c808eca0e039f50San Mehat            } else {
1010a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Unexpected response code %d", code));
1011b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return false;
1012b104340496e3a531e26c8f428c808eca0e039f50San Mehat            }
1013b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
1014a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        Slog.e(TAG, "Got an empty response");
1015b104340496e3a531e26c8f428c808eca0e039f50San Mehat        return false;
1016b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
1017b104340496e3a531e26c8f428c808eca0e039f50San Mehat
1018207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void notifyShareAvailabilityChange(String method, final boolean avail) {
10197fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        if (!method.equals("ums")) {
1020a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat           Slog.w(TAG, "Ignoring unsupported share method {" + method + "}");
10217fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat           return;
10227fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
10231f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat
10244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
10254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for (int i = mListeners.size() -1; i >= 0; i--) {
10264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                MountServiceBinderListener bl = mListeners.get(i);
10271f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                try {
1028b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    bl.mListener.onUsbMassStorageConnectionChanged(avail);
10294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (RemoteException rex) {
1030a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener dead");
10314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(i);
10321f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                } catch (Exception ex) {
1033a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener failed", ex);
10341f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                }
10351f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat            }
10364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        }
10377fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
1038207e538350665cea00e1aa70b8094beca4a34e45San Mehat        if (mBooted == true) {
10396a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat            sendUmsIntent(avail);
10406a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat        } else {
10416a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat            mSendUmsConnectedOnBoot = avail;
10421f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat        }
10432fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat
10442fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat        final String path = Environment.getExternalStorageDirectory().getPath();
10452fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat        if (avail == false && getVolumeState(path).equals(Environment.MEDIA_SHARED)) {
10462fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            /*
10472fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat             * USB mass storage disconnected while enabled
10482fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat             */
10492fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            new Thread() {
10505af0b916f850486cff4797355bf9e7dc3352fe00Jason parks                @Override
10512fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                public void run() {
10522fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    try {
10532fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        int rc;
1054a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        Slog.w(TAG, "Disabling UMS after cable disconnect");
10552fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        doShareUnshareVolume(path, "ums", false);
10562fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
1057a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.e(TAG, String.format(
10582fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                                    "Failed to remount {%s} on UMS enabled-disconnect (%d)",
10592fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                                            path, rc));
10602fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        }
10612fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    } catch (Exception ex) {
1062a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        Slog.w(TAG, "Failed to mount media on UMS enabled-disconnect", ex);
10632fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    }
10642fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                }
10652fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            }.start();
10662fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat        }
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1069a5250c93928e256738125b265e10c96c3575597eMike Lockwood    private void sendStorageIntent(String action, String path) {
1070a5250c93928e256738125b265e10c96c3575597eMike Lockwood        Intent intent = new Intent(action, Uri.parse("file://" + path));
1071a5250c93928e256738125b265e10c96c3575597eMike Lockwood        // add StorageVolume extra
1072a5250c93928e256738125b265e10c96c3575597eMike Lockwood        intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mVolumeMap.get(path));
1073a5250c93928e256738125b265e10c96c3575597eMike Lockwood        Slog.d(TAG, "sendStorageIntent " + intent);
1074a5250c93928e256738125b265e10c96c3575597eMike Lockwood        mContext.sendBroadcast(intent);
1075a5250c93928e256738125b265e10c96c3575597eMike Lockwood    }
1076a5250c93928e256738125b265e10c96c3575597eMike Lockwood
10776a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private void sendUmsIntent(boolean c) {
10786a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat        mContext.sendBroadcast(
10796a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                new Intent((c ? Intent.ACTION_UMS_CONNECTED : Intent.ACTION_UMS_DISCONNECTED)));
10806a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    }
10816a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat
1082207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void validatePermission(String perm) {
10834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
10844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            throw new SecurityException(String.format("Requires %s permission", perm));
10854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        }
10867fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
10877fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
10882f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    // Storage list XML tags
10892f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    private static final String TAG_STORAGE_LIST = "StorageList";
10902f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    private static final String TAG_STORAGE = "storage";
10912f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
10922f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    private void readStorageList(Resources resources) {
10932f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        int id = com.android.internal.R.xml.storage_list;
10942f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        XmlResourceParser parser = resources.getXml(id);
10952f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        AttributeSet attrs = Xml.asAttributeSet(parser);
10962f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
10972f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        try {
10982f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            XmlUtils.beginDocument(parser, TAG_STORAGE_LIST);
10992f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            while (true) {
11002f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                XmlUtils.nextElement(parser);
11012f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
11022f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                String element = parser.getName();
11032f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                if (element == null) break;
11042f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
11052f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                if (TAG_STORAGE.equals(element)) {
11062f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    TypedArray a = resources.obtainAttributes(attrs,
11072f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage);
11082f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
11092f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    CharSequence path = a.getText(
11102f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_mountPoint);
11112f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    CharSequence description = a.getText(
11122f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_storageDescription);
11132f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    boolean primary = a.getBoolean(
11142f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_primary, false);
11152f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    boolean removable = a.getBoolean(
11162f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_removable, false);
11172f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    boolean emulated = a.getBoolean(
11182f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_emulated, false);
11192f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    int mtpReserve = a.getInt(
11202f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_mtpReserve, 0);
11212f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
11222f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    Slog.d(TAG, "got storage path: " + path + " description: " + description +
11232f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            " primary: " + primary + " removable: " + removable +
11242f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            " emulated: " + emulated +  " mtpReserve: " + mtpReserve);
11252f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    if (path == null || description == null) {
11262f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        Slog.e(TAG, "path or description is null in readStorageList");
11272f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    } else {
1128a5250c93928e256738125b265e10c96c3575597eMike Lockwood                        String pathString = path.toString();
1129a5250c93928e256738125b265e10c96c3575597eMike Lockwood                        StorageVolume volume = new StorageVolume(pathString,
11302f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                                description.toString(), removable, emulated, mtpReserve);
11312f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        if (primary) {
11322f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            if (mPrimaryVolume == null) {
11332f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                                mPrimaryVolume = volume;
11342f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            } else {
11352f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                                Slog.e(TAG, "multiple primary volumes in storage list");
11362f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            }
11372f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        }
11382f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        if (mPrimaryVolume == volume) {
11392f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            // primay volume must be first
11402f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            mVolumes.add(0, volume);
11412f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        } else {
11422f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            mVolumes.add(volume);
11432f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        }
1144a5250c93928e256738125b265e10c96c3575597eMike Lockwood                        mVolumeMap.put(pathString, volume);
11452f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    }
11462f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    a.recycle();
11472f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                }
11482f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            }
11492f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        } catch (XmlPullParserException e) {
11502f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            throw new RuntimeException(e);
11512f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        } catch (IOException e) {
11522f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            throw new RuntimeException(e);
11532f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        } finally {
1154fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood            // compute storage ID for each volume
1155fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood            int length = mVolumes.size();
1156fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood            for (int i = 0; i < length; i++) {
1157fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood                mVolumes.get(i).setStorageId(i);
1158fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood            }
11592f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            parser.close();
11602f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        }
11612f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    }
11622f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1164207e538350665cea00e1aa70b8094beca4a34e45San Mehat     * Constructs a new MountService instance
1165207e538350665cea00e1aa70b8094beca4a34e45San Mehat     *
1166207e538350665cea00e1aa70b8094beca4a34e45San Mehat     * @param context  Binder context for this service
1167207e538350665cea00e1aa70b8094beca4a34e45San Mehat     */
1168207e538350665cea00e1aa70b8094beca4a34e45San Mehat    public MountService(Context context) {
1169207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mContext = context;
11702f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        Resources resources = context.getResources();
11712f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        readStorageList(resources);
11722f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
11732f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        if (mPrimaryVolume != null) {
11742f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            mExternalStoragePath = mPrimaryVolume.getPath();
11752f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            mEmulateExternalStorage = mPrimaryVolume.isEmulated();
11762f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            if (mEmulateExternalStorage) {
11772f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                Slog.d(TAG, "using emulated external storage");
11782f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                mVolumeStates.put(mExternalStoragePath, Environment.MEDIA_MOUNTED);
11792f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            }
118003559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood        }
118103559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood
1182207e538350665cea00e1aa70b8094beca4a34e45San Mehat        // XXX: This will go away soon in favor of IMountServiceObserver
1183207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mPms = (PackageManagerService) ServiceManager.getService("package");
1184207e538350665cea00e1aa70b8094beca4a34e45San Mehat
1185207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mContext.registerReceiver(mBroadcastReceiver,
1186207e538350665cea00e1aa70b8094beca4a34e45San Mehat                new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
1187207e538350665cea00e1aa70b8094beca4a34e45San Mehat
11885f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandlerThread = new HandlerThread("MountService");
11895f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandlerThread.start();
11905f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandler = new MountServiceHandler(mHandlerThread.getLooper());
11915f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler
1192a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        // Add OBB Action Handler to MountService thread.
1193a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());
1194a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1195c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen        /*
1196c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen         * Vold does not run in the simulator, so pretend the connector thread
1197c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen         * ran and did its thing.
1198c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen         */
1199c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen        if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
1200c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen            mReady = true;
1201c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen            mUmsEnabling = true;
1202c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen            return;
1203c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen        }
1204c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen
1205305bcbf0c961840c4505770d084a1caacc074dbbKenny Root        /*
1206305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * Create the connection to vold with a maximum queue of twice the
1207305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * amount of containers we'd ever expect to have. This keeps an
1208305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * "asec list" from blocking a thread repeatedly.
1209305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         */
1210305bcbf0c961840c4505770d084a1caacc074dbbKenny Root        mConnector = new NativeDaemonConnector(this, "vold",
1211305bcbf0c961840c4505770d084a1caacc074dbbKenny Root                PackageManagerService.MAX_CONTAINERS * 2, VOLD_TAG);
1212207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mReady = false;
1213305bcbf0c961840c4505770d084a1caacc074dbbKenny Root        Thread thread = new Thread(mConnector, VOLD_TAG);
1214207e538350665cea00e1aa70b8094beca4a34e45San Mehat        thread.start();
1215207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
1216207e538350665cea00e1aa70b8094beca4a34e45San Mehat
1217207e538350665cea00e1aa70b8094beca4a34e45San Mehat    /**
12184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Exposed API calls below here
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12207fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
12214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public void registerListener(IMountServiceListener listener) {
12224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
12234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            MountServiceBinderListener bl = new MountServiceBinderListener(listener);
12244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            try {
12254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                listener.asBinder().linkToDeath(bl, 0);
12264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListeners.add(bl);
12274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } catch (RemoteException rex) {
1228a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to link to listener death");
12294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
12307fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public void unregisterListener(IMountServiceListener listener) {
12344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
12354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for(MountServiceBinderListener bl : mListeners) {
12364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                if (bl.mListener == listener) {
12374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(mListeners.indexOf(bl));
12384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    return;
12394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
12404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12446ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    public void shutdown(final IMountShutdownObserver observer) {
12454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.SHUTDOWN);
12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1247a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        Slog.i(TAG, "Shutting down");
1248f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood        synchronized (mVolumeStates) {
1249f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            for (String path : mVolumeStates.keySet()) {
1250f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                String state = mVolumeStates.get(path);
1251f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood
1252f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                if (state.equals(Environment.MEDIA_SHARED)) {
1253f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    /*
1254f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * If the media is currently shared, unshare it.
1255f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * XXX: This is still dangerous!. We should not
1256f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * be rebooting at *all* if UMS is enabled, since
1257f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * the UMS host could have dirty FAT cache entries
1258f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * yet to flush.
1259f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     */
1260f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    setUsbMassStorageEnabled(false);
1261f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                } else if (state.equals(Environment.MEDIA_CHECKING)) {
1262f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    /*
1263f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * If the media is being checked, then we need to wait for
1264f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * it to complete before being able to proceed.
1265f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     */
1266f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    // XXX: @hackbod - Should we disable the ANR timer here?
1267f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    int retries = 30;
1268f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
1269f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        try {
1270f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                            Thread.sleep(1000);
1271f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        } catch (InterruptedException iex) {
1272f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                            Slog.e(TAG, "Interrupted while waiting for media", iex);
1273f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                            break;
1274f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        }
1275f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        state = Environment.getExternalStorageState();
1276f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    }
1277f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    if (retries == 0) {
1278f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        Slog.e(TAG, "Timed out waiting for media to check");
1279f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    }
12804270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
12817fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
1282f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                if (state.equals(Environment.MEDIA_MOUNTED)) {
1283f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    // Post a unmount message.
1284f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    ShutdownCallBack ucb = new ShutdownCallBack(path, observer);
1285f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
1286f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                } else if (observer != null) {
1287f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    /*
1288f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * Observer is waiting for onShutDownComplete when we are done.
1289f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * Since nothing will be done send notification directly so shutdown
1290f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * sequence can continue.
1291f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     */
1292f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    try {
1293f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        observer.onShutDownComplete(StorageResultCode.OperationSucceeded);
1294f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    } catch (RemoteException e) {
1295f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        Slog.w(TAG, "RemoteException when shutting down");
1296f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    }
1297f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                }
12985d0db4d356346bee68aec9a124df70dbaa9aaed1Johan Alfven            }
12991f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat        }
13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13020eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private boolean getUmsEnabling() {
13030eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        synchronized (mListeners) {
13040eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            return mUmsEnabling;
13050eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
13060eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
13070eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
13080eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private void setUmsEnabling(boolean enable) {
13090eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        synchronized (mListeners) {
1310fc71125104650c61ab5b04f4c943de761d58cba6Tony Wu            mUmsEnabling = enable;
13110eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
13120eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
13130eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
1314b104340496e3a531e26c8f428c808eca0e039f50San Mehat    public boolean isUsbMassStorageConnected() {
1315207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
13167fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
13170eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (getUmsEnabling()) {
1318b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return true;
1319b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
1320b104340496e3a531e26c8f428c808eca0e039f50San Mehat        return doGetShareMethodAvailable("ums");
13214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13230eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    public void setUsbMassStorageEnabled(boolean enable) {
1324207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
13250eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
13260eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
13270eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        // TODO: Add support for multiple share methods
1328b104340496e3a531e26c8f428c808eca0e039f50San Mehat
13290eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        /*
13300eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         * If the volume is mounted and we're enabling then unmount it
13310eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         */
13320eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        String path = Environment.getExternalStorageDirectory().getPath();
13330eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        String vs = getVolumeState(path);
13340eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        String method = "ums";
13350eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
13360eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            // Override for isUsbMassStorageEnabled()
13370eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            setUmsEnabling(enable);
13380eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true);
13390eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb));
13400eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            // Clear override
13410eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            setUmsEnabling(false);
13420eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
13430eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        /*
13440eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         * If we disabled UMS then mount the volume
13450eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         */
13460eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (!enable) {
13470eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            doShareUnshareVolume(path, method, enable);
13480eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
1349a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to remount " + path +
13500eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                        " after disabling share method " + method);
13510eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                /*
13520eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * Even though the mount failed, the unshare didn't so don't indicate an error.
13530eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * The mountVolume() call will have set the storage state and sent the necessary
13540eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * broadcasts.
13550eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 */
13560eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            }
13570eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
13584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1360b104340496e3a531e26c8f428c808eca0e039f50San Mehat    public boolean isUsbMassStorageEnabled() {
1361207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1362b104340496e3a531e26c8f428c808eca0e039f50San Mehat        return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums");
13639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13649ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
13664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * @return state of the volume at the specified mount point
13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String getVolumeState(String mountPoint) {
1369f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood        synchronized (mVolumeStates) {
1370f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            String state = mVolumeStates.get(mountPoint);
1371f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            if (state == null) {
1372f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
1373f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                throw new IllegalArgumentException();
1374f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            }
13754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1376f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            return state;
1377f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood        }
13789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1380e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root    public boolean isExternalStorageEmulated() {
1381e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root        return mEmulateExternalStorage;
1382e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root    }
1383e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root
13844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int mountVolume(String path) {
13854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1387207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1388207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return doMountVolume(path);
13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1391c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    public void unmountVolume(String path, boolean force) {
13924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1393207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13958a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        String volState = getVolumeState(path);
1396a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path + " force = " + force);
13978a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        if (Environment.MEDIA_UNMOUNTED.equals(volState) ||
13988a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_REMOVED.equals(volState) ||
13998a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_SHARED.equals(volState) ||
14008a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_UNMOUNTABLE.equals(volState)) {
14018a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            // Media already unmounted or cannot be unmounted.
14028a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            // TODO return valid return code when adding observer call back.
14038a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            return;
14048a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
1405c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        UnmountCallBack ucb = new UnmountCallBack(path, force);
1406c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
14074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int formatVolume(String path) {
14104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1411207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1413207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return doFormatVolume(path);
14149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14153697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1416c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat    public int []getStorageUsers(String path) {
1417c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1418c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        waitForReady();
1419c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        try {
1420c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            String[] r = mConnector.doListCommand(
1421c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                    String.format("storage users %s", path),
1422c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                            VoldResponseCode.StorageUsersListResult);
1423c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            // FMT: <pid> <process name>
1424c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            int[] data = new int[r.length];
1425c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            for (int i = 0; i < r.length; i++) {
1426c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                String []tok = r[i].split(" ");
1427c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                try {
1428c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                    data[i] = Integer.parseInt(tok[0]);
1429c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                } catch (NumberFormatException nfe) {
1430a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
1431c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                    return new int[0];
1432c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                }
1433c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            }
1434c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            return data;
1435c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        } catch (NativeDaemonConnectorException e) {
1436a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Failed to retrieve storage users list", e);
1437c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            return new int[0];
1438c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        }
1439c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat    }
1440c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat
1441b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private void warnOnNotMounted() {
1442b104340496e3a531e26c8f428c808eca0e039f50San Mehat        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
1443a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.w(TAG, "getSecureContainerList() called when storage not mounted");
1444b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
1445b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
1446b104340496e3a531e26c8f428c808eca0e039f50San Mehat
14474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String[] getSecureContainerList() {
14484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
1449207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1450b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1451f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
14524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
14534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult);
14544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
14554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            return new String[0];
145602735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
14573697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
14583697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
14594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int createSecureContainer(String id, int sizeMb, String fstype,
14604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                                    String key, int ownerUid) {
14614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_CREATE);
1462207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1463b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
14644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1465b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
14664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        String cmd = String.format("asec create %s %d %s %s %d", id, sizeMb, fstype, key, ownerUid);
14674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
14684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(cmd);
14694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1470b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
147102735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1472a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1473a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        if (rc == StorageResultCode.OperationSucceeded) {
1474a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            synchronized (mAsecMountSet) {
1475a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                mAsecMountSet.add(id);
1476a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1477a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
14784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
14793697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
14803697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
14814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int finalizeSecureContainer(String id) {
14824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_CREATE);
1483b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
14844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1485b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
14864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
14874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(String.format("asec finalize %s", id));
1488a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            /*
1489a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             * Finalization does a remount, so no need
1490a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             * to update mAsecMountSet
1491a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             */
14924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1493b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
149402735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
14954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
14963697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
14973697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1498d970998b0d489774ad1c5b94b47d233912f00214San Mehat    public int destroySecureContainer(String id, boolean force) {
14994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_DESTROY);
1500207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1501b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1502f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
1503aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
1504aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
1505aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
1506aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
1507aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
1508aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
1509aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
1510aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
1511b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
15124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1513d970998b0d489774ad1c5b94b47d233912f00214San Mehat            mConnector.doCommand(String.format("asec destroy %s%s", id, (force ? " force" : "")));
15144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1515d970998b0d489774ad1c5b94b47d233912f00214San Mehat            int code = e.getCode();
1516d970998b0d489774ad1c5b94b47d233912f00214San Mehat            if (code == VoldResponseCode.OpFailedStorageBusy) {
1517d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedStorageBusy;
1518d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else {
1519d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedInternalError;
1520d970998b0d489774ad1c5b94b47d233912f00214San Mehat            }
152102735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1522a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1523a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        if (rc == StorageResultCode.OperationSucceeded) {
1524a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            synchronized (mAsecMountSet) {
1525a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                if (mAsecMountSet.contains(id)) {
1526a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                    mAsecMountSet.remove(id);
1527a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                }
1528a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1529a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1530a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
15314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
15323697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
15339ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
15344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int mountSecureContainer(String id, String key, int ownerUid) {
15354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
1536207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1537b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
15384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1539a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        synchronized (mAsecMountSet) {
1540a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            if (mAsecMountSet.contains(id)) {
1541a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageMounted;
1542a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1543a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1544a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1545b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
15464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        String cmd = String.format("asec mount %s %s %d", id, key, ownerUid);
15474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
15484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(cmd);
15494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1550f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            int code = e.getCode();
1551f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            if (code != VoldResponseCode.OpFailedStorageBusy) {
1552f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root                rc = StorageResultCode.OperationFailedInternalError;
1553f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            }
155402735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
15556cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
15566cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        if (rc == StorageResultCode.OperationSucceeded) {
15576cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            synchronized (mAsecMountSet) {
15586cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat                mAsecMountSet.add(id);
15596cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
15606cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
15614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
15623697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
15633697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1564d970998b0d489774ad1c5b94b47d233912f00214San Mehat    public int unmountSecureContainer(String id, boolean force) {
15654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
1566207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1567b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
15684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
15696cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        synchronized (mAsecMountSet) {
15706cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            if (!mAsecMountSet.contains(id)) {
1571a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageNotMounted;
15726cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
15736cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat         }
15746cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
1575aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
1576aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
1577aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
1578aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
1579aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
1580aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
1581aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
1582aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
1583b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
1584d970998b0d489774ad1c5b94b47d233912f00214San Mehat        String cmd = String.format("asec unmount %s%s", id, (force ? " force" : ""));
15854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
15864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(cmd);
15874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1588d970998b0d489774ad1c5b94b47d233912f00214San Mehat            int code = e.getCode();
1589d970998b0d489774ad1c5b94b47d233912f00214San Mehat            if (code == VoldResponseCode.OpFailedStorageBusy) {
1590d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedStorageBusy;
1591d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else {
1592d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedInternalError;
1593d970998b0d489774ad1c5b94b47d233912f00214San Mehat            }
159402735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
15956cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
15966cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        if (rc == StorageResultCode.OperationSucceeded) {
15976cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            synchronized (mAsecMountSet) {
15986cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat                mAsecMountSet.remove(id);
15996cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
16006cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
16014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
16029dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat    }
16039dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat
16046cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    public boolean isSecureContainerMounted(String id) {
16056cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
16066cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        waitForReady();
16076cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        warnOnNotMounted();
16086cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
16096cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        synchronized (mAsecMountSet) {
16106cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            return mAsecMountSet.contains(id);
16116cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
16126cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    }
16136cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
16144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int renameSecureContainer(String oldId, String newId) {
16154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_RENAME);
1616207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1617b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
16184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1619a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        synchronized (mAsecMountSet) {
162085451ee15fdf6cae371dc3005441988c7d426401San Mehat            /*
16219ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks             * Because a mounted container has active internal state which cannot be
162285451ee15fdf6cae371dc3005441988c7d426401San Mehat             * changed while active, we must ensure both ids are not currently mounted.
162385451ee15fdf6cae371dc3005441988c7d426401San Mehat             */
162485451ee15fdf6cae371dc3005441988c7d426401San Mehat            if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
1625a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageMounted;
1626a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1627a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1628a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1629b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
16304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        String cmd = String.format("asec rename %s %s", oldId, newId);
16314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
16324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(cmd);
16334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1634b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
163502735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1636a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
16374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
163845f61040823d8c442838f75cde8760f236603daeSan Mehat    }
163945f61040823d8c442838f75cde8760f236603daeSan Mehat
16404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String getSecureContainerPath(String id) {
16414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
1642207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1643b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1644f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
16452d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        try {
16462d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            ArrayList<String> rsp = mConnector.doCommand(String.format("asec path %s", id));
16472d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            String []tok = rsp.get(0).split(" ");
164822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            int code = Integer.parseInt(tok[0]);
16492d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            if (code != VoldResponseCode.AsecPathResult) {
16502d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat                throw new IllegalStateException(String.format("Unexpected response code %d", code));
16512d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            }
16522d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            return tok[1];
16532d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        } catch (NativeDaemonConnectorException e) {
16542d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            int code = e.getCode();
16552d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            if (code == VoldResponseCode.OpFailedStorageNotFound) {
16562d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat                throw new IllegalArgumentException(String.format("Container '%s' not found", id));
165722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            } else {
16582d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat                throw new IllegalStateException(String.format("Unexpected response code %d", code));
165922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            }
166022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
166122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
1662e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu
1663e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu    public void finishMediaUpdate() {
1664e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
1665e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu    }
166602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1667a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
1668a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        if (callerUid == android.os.Process.SYSTEM_UID) {
1669a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return true;
1670a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1671a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
167202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        if (packageName == null) {
167302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            return false;
167402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
167502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
167602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        final int packageUid = mPms.getPackageUid(packageName);
167702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
167802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        if (DEBUG_OBB) {
167902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
168002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root                    packageUid + ", callerUid = " + callerUid);
168102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
168202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
168302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        return callerUid == packageUid;
168402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
168502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
168602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    public String getMountedObbPath(String filename) {
1687af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (filename == null) {
1688af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("filename cannot be null");
1689af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        }
1690af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
169102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        waitForReady();
169202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        warnOnNotMounted();
169302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
169402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        try {
169502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            ArrayList<String> rsp = mConnector.doCommand(String.format("obb path %s", filename));
169602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            String []tok = rsp.get(0).split(" ");
169702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            int code = Integer.parseInt(tok[0]);
169802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            if (code != VoldResponseCode.AsecPathResult) {
169902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root                throw new IllegalStateException(String.format("Unexpected response code %d", code));
170002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
170102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            return tok[1];
170202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        } catch (NativeDaemonConnectorException e) {
170302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            int code = e.getCode();
170402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            if (code == VoldResponseCode.OpFailedStorageNotFound) {
1705a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                return null;
170602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            } else {
170702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root                throw new IllegalStateException(String.format("Unexpected response code %d", code));
170802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
170902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
171002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
171102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
171202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    public boolean isObbMounted(String filename) {
1713af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (filename == null) {
1714af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("filename cannot be null");
1715af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        }
1716af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1717a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        synchronized (mObbMounts) {
1718af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            return mObbPathToStateMap.containsKey(filename);
1719a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1720a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
1721a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1722af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    public void mountObb(String filename, String key, IObbActionListener token, int nonce)
1723735de3b38abbd6564082a819377673ee593744a6Kenny Root            throws RemoteException {
1724f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root        if (filename == null) {
1725f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root            throw new IllegalArgumentException("filename cannot be null");
1726f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root        }
1727f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root
1728af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (token == null) {
1729af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("token cannot be null");
17302942391801b79816c5eb77d7ac94c4a65f26af48Kenny Root        }
1731735de3b38abbd6564082a819377673ee593744a6Kenny Root
1732af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final int callerUid = Binder.getCallingUid();
1733af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final ObbState obbState = new ObbState(filename, callerUid, token, nonce);
1734af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final ObbAction action = new MountObbAction(obbState, key);
1735a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
1736a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1737a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        if (DEBUG_OBB)
1738a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            Slog.i(TAG, "Send to OBB handler: " + action.toString());
173902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
174002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1741af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    public void unmountObb(String filename, boolean force, IObbActionListener token, int nonce)
1742af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throws RemoteException {
1743f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root        if (filename == null) {
1744f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root            throw new IllegalArgumentException("filename cannot be null");
1745f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root        }
1746f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root
1747af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final int callerUid = Binder.getCallingUid();
1748af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final ObbState obbState = new ObbState(filename, callerUid, token, nonce);
1749af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final ObbAction action = new UnmountObbAction(obbState, force);
1750a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
1751a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1752a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        if (DEBUG_OBB)
1753a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            Slog.i(TAG, "Send to OBB handler: " + action.toString());
1754a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
175502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
17565af0b916f850486cff4797355bf9e7dc3352fe00Jason parks    public int decryptStorage(String password) {
1757f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (TextUtils.isEmpty(password)) {
1758f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            throw new IllegalArgumentException("password cannot be empty");
17595af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        }
17605af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
17618888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
17628888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks                "no permission to access the crypt keeper");
17635af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
17645af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        waitForReady();
17655af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
17665af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        if (DEBUG_EVENTS) {
17675af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            Slog.i(TAG, "decrypting storage...");
17685af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        }
17695af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
17705af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        try {
17719ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            ArrayList<String> rsp = mConnector.doCommand("cryptfs checkpw " + password);
1772f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            String[] tokens = rsp.get(0).split(" ");
17739ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
1774f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            if (tokens == null || tokens.length != 2) {
17759ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                return -1;
17769ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            }
17779ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
1778f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            int code = Integer.parseInt(tokens[1]);
17799ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
17809ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            if (code == 0) {
17819ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                // Decrypt was successful. Post a delayed message before restarting in order
17829ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                // to let the UI to clear itself
17839ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                mHandler.postDelayed(new Runnable() {
17849ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                    public void run() {
17859ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                        mConnector.doCommand(String.format("cryptfs restart"));
17869ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                    }
1787f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks                }, 1000); // 1 second
17889ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            }
17899ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
17909ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            return code;
17915af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        } catch (NativeDaemonConnectorException e) {
17925af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            // Decryption failed
17935af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            return e.getCode();
17945af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        }
17955af0b916f850486cff4797355bf9e7dc3352fe00Jason parks    }
17965af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
179756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks    public int encryptStorage(String password) {
1798f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (TextUtils.isEmpty(password)) {
1799f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            throw new IllegalArgumentException("password cannot be empty");
180056aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        }
180156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
18028888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
18038888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks            "no permission to access the crypt keeper");
180456aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
180556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        waitForReady();
180656aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
180756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        if (DEBUG_EVENTS) {
18088888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks            Slog.i(TAG, "encrypting storage...");
180956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        }
181056aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
181156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        try {
18129ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            mConnector.doCommand(String.format("cryptfs enablecrypto inplace %s", password));
181356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        } catch (NativeDaemonConnectorException e) {
181456aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks            // Encryption failed
181556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks            return e.getCode();
181656aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        }
181756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
181856aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        return 0;
181956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks    }
182056aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
1821f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks    public int changeEncryptionPassword(String password) {
1822f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (TextUtils.isEmpty(password)) {
1823f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            throw new IllegalArgumentException("password cannot be empty");
1824f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        }
1825f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1826f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
1827f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            "no permission to access the crypt keeper");
1828f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1829f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        waitForReady();
1830f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1831f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (DEBUG_EVENTS) {
1832f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            Slog.i(TAG, "changing encryption password...");
1833f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        }
1834f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1835f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        try {
1836f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            ArrayList<String> response = mConnector.doCommand("cryptfs changepw " + password);
1837f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1838f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            String[] tokens = response.get(0).split(" ");
1839f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1840f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            if (tokens == null || tokens.length != 2) {
1841f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks                return -1;
1842f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            }
1843f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1844f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            return Integer.parseInt(tokens[1]);
1845f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        } catch (NativeDaemonConnectorException e) {
1846f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            // Encryption failed
1847f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            return e.getCode();
1848f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        }
1849f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks    }
1850f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
18512f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    public Parcelable[] getVolumeList() {
18522f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        synchronized(mVolumes) {
18532f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            int size = mVolumes.size();
18542f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            Parcelable[] result = new Parcelable[size];
18552f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            for (int i = 0; i < size; i++) {
18562f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                result[i] = mVolumes.get(i);
1857d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood            }
1858d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood            return result;
1859d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood        }
1860d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood    }
1861d967f4664f40f9a4c5262a44b19df9bbdf457d8aMike Lockwood
1862af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private void addObbStateLocked(ObbState obbState) throws RemoteException {
1863af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IBinder binder = obbState.getBinder();
1864af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        List<ObbState> obbStates = mObbMounts.get(binder);
18655919ac6b4188285324646772501ef4b97b353cf4Kenny Root
1866af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (obbStates == null) {
1867af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbStates = new ArrayList<ObbState>();
1868af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            mObbMounts.put(binder, obbStates);
1869af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        } else {
1870af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            for (final ObbState o : obbStates) {
1871af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (o.filename.equals(obbState.filename)) {
1872af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    throw new IllegalStateException("Attempt to add ObbState twice. "
1873af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            + "This indicates an error in the MountService logic.");
18745919ac6b4188285324646772501ef4b97b353cf4Kenny Root                }
18755919ac6b4188285324646772501ef4b97b353cf4Kenny Root            }
187602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
187702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1878af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        obbStates.add(obbState);
1879af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        try {
1880af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbState.link();
1881af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        } catch (RemoteException e) {
1882af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            /*
1883af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * The binder died before we could link it, so clean up our state
1884af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * and return failure.
1885af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             */
1886af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbStates.remove(obbState);
1887af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.isEmpty()) {
1888af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mObbMounts.remove(binder);
188905105f7abe02b2dff91d6260b3628c8b97816babKenny Root            }
18905919ac6b4188285324646772501ef4b97b353cf4Kenny Root
1891af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            // Rethrow the error so mountObb can get it
1892af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw e;
189302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
1894af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1895af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        mObbPathToStateMap.put(obbState.filename, obbState);
1896a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
189702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1898af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private void removeObbStateLocked(ObbState obbState) {
1899af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IBinder binder = obbState.getBinder();
1900af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final List<ObbState> obbStates = mObbMounts.get(binder);
1901af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (obbStates != null) {
1902af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.remove(obbState)) {
1903af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                obbState.unlink();
1904af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
1905af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.isEmpty()) {
1906af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mObbMounts.remove(binder);
1907af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
190838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
1909af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1910af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        mObbPathToStateMap.remove(obbState.filename);
191138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    }
191238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
1913a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private class ObbActionHandler extends Handler {
1914a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private boolean mBound = false;
1915480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root        private final List<ObbAction> mActions = new LinkedList<ObbAction>();
1916a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1917a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbActionHandler(Looper l) {
1918a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(l);
1919a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1920a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1921a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
1922a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleMessage(Message msg) {
1923a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            switch (msg.what) {
1924a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_RUN_ACTION: {
1925480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                    final ObbAction action = (ObbAction) msg.obj;
1926a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1927a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
1928a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
1929a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1930a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // If a bind was already initiated we don't really
1931a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // need to do anything. The pending install
1932a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // will be processed later on.
1933a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (!mBound) {
1934a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // If this is the only one pending we might
1935a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // have to bind to the service again.
1936a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (!connectToService()) {
1937a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            Slog.e(TAG, "Failed to bind to media container service");
1938a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.handleError();
1939a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            return;
1940a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
1941a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
1942735de3b38abbd6564082a819377673ee593744a6Kenny Root
1943735de3b38abbd6564082a819377673ee593744a6Kenny Root                    mActions.add(action);
1944a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
1945a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
1946a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_BOUND: {
1947a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
1948a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_BOUND");
1949a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (msg.obj != null) {
1950a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mContainerService = (IMediaContainerService) msg.obj;
1951a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
1952a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mContainerService == null) {
1953a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Something seriously wrong. Bail out
1954a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.e(TAG, "Cannot bind to media container service");
1955a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        for (ObbAction action : mActions) {
1956a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            // Indicate service bind error
1957a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.handleError();
1958a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
1959a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mActions.clear();
1960a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else if (mActions.size() > 0) {
1961480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                        final ObbAction action = mActions.get(0);
1962a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (action != null) {
1963a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.execute(this);
1964a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
1965a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else {
1966a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Should never happen ideally.
1967a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.w(TAG, "Empty queue");
1968a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
1969a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
1970a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
1971a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_RECONNECT: {
1972a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
1973a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_RECONNECT");
1974a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() > 0) {
1975a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (mBound) {
1976a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            disconnectService();
1977a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
1978a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (!connectToService()) {
1979a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            Slog.e(TAG, "Failed to bind to media container service");
1980a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            for (ObbAction action : mActions) {
1981a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                                // Indicate service bind error
1982a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                                action.handleError();
1983a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            }
1984a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            mActions.clear();
1985a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
1986a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
1987a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
1988a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
1989a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_UNBIND: {
1990a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
1991a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_UNBIND");
1992a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1993a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // Delete pending install
1994a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() > 0) {
1995a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mActions.remove(0);
1996a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
1997a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() == 0) {
1998a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (mBound) {
1999a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            disconnectService();
2000a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2001a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else {
2002a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // There are more pending requests in queue.
2003a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Just post MCS_BOUND message to trigger processing
2004a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // of next pending install.
2005a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
2006a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2007a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
2008a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2009af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                case OBB_FLUSH_MOUNT_STATE: {
2010af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    final String path = (String) msg.obj;
2011af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2012af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    if (DEBUG_OBB)
2013af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        Slog.i(TAG, "Flushing all OBB state for path " + path);
2014af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2015af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    synchronized (mObbMounts) {
2016af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
2017af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2018af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        final Iterator<Entry<String, ObbState>> i =
2019af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                mObbPathToStateMap.entrySet().iterator();
2020af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        while (i.hasNext()) {
2021af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            final Entry<String, ObbState> obbEntry = i.next();
2022af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2023af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            /*
2024af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * If this entry's source file is in the volume path
2025af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * that got unmounted, remove it because it's no
2026af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * longer valid.
2027af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             */
2028af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            if (obbEntry.getKey().startsWith(path)) {
2029af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                obbStatesToRemove.add(obbEntry.getValue());
2030af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            }
2031af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        }
2032af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2033af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        for (final ObbState obbState : obbStatesToRemove) {
2034af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            if (DEBUG_OBB)
2035af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                Slog.i(TAG, "Removing state for " + obbState.filename);
2036af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2037af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            removeObbStateLocked(obbState);
2038af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2039af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            try {
2040af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                obbState.token.onObbResult(obbState.filename, obbState.nonce,
2041af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                        OnObbStateChangeListener.UNMOUNTED);
2042af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            } catch (RemoteException e) {
2043af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                Slog.i(TAG, "Couldn't send unmount notification for  OBB: "
2044af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                        + obbState.filename);
2045af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            }
2046af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        }
2047af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    }
2048af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    break;
2049af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                }
205002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
205102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
205202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2053a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private boolean connectToService() {
2054a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
2055a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "Trying to bind to DefaultContainerService");
2056a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2057a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
2058a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) {
2059a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mBound = true;
2060a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                return true;
206102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
2062a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return false;
2063a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2064a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2065a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private void disconnectService() {
2066a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mContainerService = null;
2067a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mBound = false;
2068a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mContext.unbindService(mDefContainerConn);
206902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
207002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
207102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2072a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    abstract class ObbAction {
2073a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private static final int MAX_RETRIES = 3;
2074a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private int mRetries;
207502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2076a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbState mObbState;
2077a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2078a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbAction(ObbState obbState) {
2079a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbState = obbState;
208002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
208102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2082a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void execute(ObbActionHandler handler) {
2083a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            try {
2084a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
2085a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.i(TAG, "Starting to execute action: " + this.toString());
2086a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mRetries++;
2087a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (mRetries > MAX_RETRIES) {
2088a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
2089480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                    mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
2090a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    handleError();
2091a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    return;
2092a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                } else {
2093a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    handleExecute();
2094a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
2095a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "Posting install MCS_UNBIND");
2096a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
2097a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2098a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            } catch (RemoteException e) {
2099a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
2100a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.i(TAG, "Posting install MCS_RECONNECT");
2101a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
2102a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            } catch (Exception e) {
2103a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
2104a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.d(TAG, "Error handling OBB action", e);
2105a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                handleError();
210617eb6fb07cc6965f09c51adc70b3c291f57a784aKenny Root                mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
210702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
2108a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
210902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
211005105f7abe02b2dff91d6260b3628c8b97816babKenny Root        abstract void handleExecute() throws RemoteException, IOException;
2111a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        abstract void handleError();
211238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
211338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        protected ObbInfo getObbInfo() throws IOException {
211438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            ObbInfo obbInfo;
211538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            try {
211638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                obbInfo = mContainerService.getObbInfo(mObbState.filename);
211738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } catch (RemoteException e) {
211838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
211938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                        + mObbState.filename);
212038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                obbInfo = null;
212138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
212238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            if (obbInfo == null) {
212338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                throw new IOException("Couldn't read OBB file: " + mObbState.filename);
212438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
212538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return obbInfo;
212638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
212738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2128af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        protected void sendNewStatusOrIgnore(int status) {
2129af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (mObbState == null || mObbState.token == null) {
2130af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2131af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2132af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
213338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            try {
2134af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mObbState.token.onObbResult(mObbState.filename, mObbState.nonce, status);
213538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } catch (RemoteException e) {
213638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
213738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
213838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
2139a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
2140a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2141a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class MountObbAction extends ObbAction {
2142a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private String mKey;
2143a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2144a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        MountObbAction(ObbState obbState, String key) {
2145a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(obbState);
2146a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mKey = key;
2147a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2148a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
21495af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
2150735de3b38abbd6564082a819377673ee593744a6Kenny Root        public void handleExecute() throws IOException, RemoteException {
2151af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            waitForReady();
2152af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            warnOnNotMounted();
2153af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
215438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            final ObbInfo obbInfo = getObbInfo();
215538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2156af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mObbState.callerUid)) {
2157af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
2158af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        + " which is owned by " + obbInfo.packageName);
2159af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
2160af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2161af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2162af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2163af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final boolean isMounted;
2164af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            synchronized (mObbMounts) {
2165af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                isMounted = mObbPathToStateMap.containsKey(obbInfo.filename);
2166af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2167af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (isMounted) {
2168af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
2169af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
2170af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2171af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2172af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
217338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            /*
2174af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * The filename passed in might not be the canonical name, so just
2175af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * set the filename to the canonicalized version.
217638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root             */
2177af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            mObbState.filename = obbInfo.filename;
217838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2179af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final String hashedKey;
2180af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (mKey == null) {
2181af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                hashedKey = "none";
2182af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } else {
2183af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                try {
21843b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
21853b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
21863b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
21873b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                            PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
21883b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    SecretKey key = factory.generateSecret(ks);
21893b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    BigInteger bi = new BigInteger(key.getEncoded());
21903b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    hashedKey = bi.toString(16);
2191af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } catch (NoSuchAlgorithmException e) {
21923b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
21933b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
21943b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    return;
21953b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                } catch (InvalidKeySpecException e) {
21963b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
21973b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
2198af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    return;
219938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                }
2200a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
2201a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2202af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            int rc = StorageResultCode.OperationSucceeded;
2203af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            String cmd = String.format("obb mount %s %s %d", mObbState.filename, hashedKey,
2204af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    mObbState.callerUid);
2205af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            try {
2206af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mConnector.doCommand(cmd);
2207af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } catch (NativeDaemonConnectorException e) {
2208af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                int code = e.getCode();
2209af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (code != VoldResponseCode.OpFailedStorageBusy) {
2210af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedInternalError;
2211a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2212af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2213a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2214af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (rc == StorageResultCode.OperationSucceeded) {
2215af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (DEBUG_OBB)
2216af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    Slog.d(TAG, "Successfully mounted OBB " + mObbState.filename);
221738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2218af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                synchronized (mObbMounts) {
2219af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    addObbStateLocked(mObbState);
2220a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
222138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2222af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
222302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            } else {
222405105f7abe02b2dff91d6260b3628c8b97816babKenny Root                Slog.e(TAG, "Couldn't mount OBB file: " + rc);
2225a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2226af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
222702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
222802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
222902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
22305af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
2231a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleError() {
2232af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
223302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
2234a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2235a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
2236a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public String toString() {
2237a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            StringBuilder sb = new StringBuilder();
2238a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("MountObbAction{");
2239a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("filename=");
2240a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.filename);
2241a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",callerUid=");
2242a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.callerUid);
2243a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",token=");
2244a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.token != null ? mObbState.token.toString() : "NULL");
2245af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sb.append(",binder=");
2246af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sb.append(mObbState.token != null ? mObbState.getBinder().toString() : "null");
2247a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append('}');
2248a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return sb.toString();
2249a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2250a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
2251a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2252a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class UnmountObbAction extends ObbAction {
2253a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private boolean mForceUnmount;
2254a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2255a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        UnmountObbAction(ObbState obbState, boolean force) {
2256a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(obbState);
2257a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mForceUnmount = force;
2258a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2259a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
22605af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
226138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        public void handleExecute() throws IOException {
2262af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            waitForReady();
2263af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            warnOnNotMounted();
2264af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
226538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            final ObbInfo obbInfo = getObbInfo();
2266a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2267af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final ObbState obbState;
226838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            synchronized (mObbMounts) {
2269af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                obbState = mObbPathToStateMap.get(obbInfo.filename);
2270af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
227138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2272af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbState == null) {
2273af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
2274af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2275a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
2276a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2277af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbState.callerUid != mObbState.callerUid) {
2278af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Permission denied attempting to unmount OBB " + obbInfo.filename
2279af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        + " (owned by " + obbInfo.packageName + ")");
2280af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
2281af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2282af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2283a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2284af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            mObbState.filename = obbInfo.filename;
228538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2286af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            int rc = StorageResultCode.OperationSucceeded;
2287af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            String cmd = String.format("obb unmount %s%s", mObbState.filename,
2288af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    (mForceUnmount ? " force" : ""));
2289af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            try {
2290af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mConnector.doCommand(cmd);
2291af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } catch (NativeDaemonConnectorException e) {
2292af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                int code = e.getCode();
2293af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (code == VoldResponseCode.OpFailedStorageBusy) {
2294af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedStorageBusy;
2295af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
2296af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    // If it's not mounted then we've already won.
2297af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationSucceeded;
2298af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } else {
2299af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedInternalError;
2300a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2301a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
230238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2303af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (rc == StorageResultCode.OperationSucceeded) {
2304af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                synchronized (mObbMounts) {
2305af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    removeObbStateLocked(obbState);
2306af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                }
230738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2308af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
230938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } else {
2310af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Could not mount OBB: " + mObbState.filename);
2311af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
231238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
2313a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2314a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
23155af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
2316a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleError() {
2317af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
2318a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2319a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2320a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
2321a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public String toString() {
2322a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            StringBuilder sb = new StringBuilder();
2323a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("UnmountObbAction{");
2324a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("filename=");
2325a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.filename != null ? mObbState.filename : "null");
2326a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",force=");
2327a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mForceUnmount);
2328a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",callerUid=");
2329a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.callerUid);
2330a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",token=");
2331a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.token != null ? mObbState.token.toString() : "null");
2332735de3b38abbd6564082a819377673ee593744a6Kenny Root            sb.append(",binder=");
2333af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sb.append(mObbState.token != null ? mObbState.getBinder().toString() : "null");
2334a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append('}');
2335a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return sb.toString();
2336a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
233702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
233838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
233938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    @Override
234038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
234138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
234238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            pw.println("Permission Denial: can't dump ActivityManager from from pid="
234338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
234438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                    + " without permission " + android.Manifest.permission.DUMP);
234538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return;
234638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
234738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
234838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        synchronized (mObbMounts) {
2349af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("  mObbMounts:");
235038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2351af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet().iterator();
2352af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            while (binders.hasNext()) {
2353af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Entry<IBinder, List<ObbState>> e = binders.next();
2354af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print("    Key="); pw.println(e.getKey().toString());
2355af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                final List<ObbState> obbStates = e.getValue();
235638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                for (final ObbState obbState : obbStates) {
2357af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    pw.print("      "); pw.println(obbState.toString());
235838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                }
235938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
2360af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2361af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("");
2362af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("  mObbPathToStateMap:");
2363af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
2364af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            while (maps.hasNext()) {
2365af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                final Entry<String, ObbState> e = maps.next();
2366af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print("    "); pw.print(e.getKey());
2367af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print(" -> "); pw.println(e.getValue().toString());
2368af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
236938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
237038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    }
23719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
23729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2373