MountService.java revision ecedfdc7794048cd539e3df92b641a18a05acdf7
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; 22cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Rootimport com.android.server.pm.PackageManagerService; 23c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 248888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parksimport android.Manifest; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver; 26a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ComponentName; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter; 30a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ServiceConnection; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager; 3202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.content.res.ObbInfo; 332f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.Resources; 342f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.TypedArray; 352f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.XmlResourceParser; 36ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwoodimport android.hardware.usb.UsbManager; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri; 3802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.os.Binder; 39a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.Environment; 40c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Handler; 415f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.HandlerThread; 42a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.IBinder; 435f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.Looper; 44c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Message; 452f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.os.Parcelable; 464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehatimport android.os.RemoteException; 47fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapuimport android.os.ServiceManager; 48207e538350665cea00e1aa70b8094beca4a34e45San Mehatimport android.os.SystemClock; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties; 50a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountService; 51a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountServiceListener; 52a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountShutdownObserver; 53a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IObbActionListener; 54af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Rootimport android.os.storage.OnObbStateChangeListener; 55a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.StorageResultCode; 562f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.os.storage.StorageVolume; 57f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parksimport android.text.TextUtils; 582f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.util.AttributeSet; 59a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehatimport android.util.Slog; 602f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.util.Xml; 612f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 622f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport org.xmlpull.v1.XmlPullParser; 632f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport org.xmlpull.v1.XmlPullParserException; 64a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 6538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.FileDescriptor; 6605105f7abe02b2dff91d6260b3628c8b97816babKenny Rootimport java.io.IOException; 6738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.PrintWriter; 683b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.math.BigInteger; 69735de3b38abbd6564082a819377673ee593744a6Kenny Rootimport java.security.NoSuchAlgorithmException; 703b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.InvalidKeySpecException; 713b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.KeySpec; 7222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehatimport java.util.ArrayList; 73a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.HashMap; 746cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehatimport java.util.HashSet; 7538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Iterator; 76a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.LinkedList; 77a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.List; 78a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.Map; 7938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Map.Entry; 808fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwoodimport java.util.Set; 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 823b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKey; 833b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKeyFactory; 843b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.spec.PBEKeySpec; 853b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 87b104340496e3a531e26c8f428c808eca0e039f50San Mehat * MountService implements back-end services for platform storage 88b104340496e3a531e26c8f428c808eca0e039f50San Mehat * management. 89b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @hide - Applications should use android.os.storage.StorageManager 90b104340496e3a531e26c8f428c808eca0e039f50San Mehat * to access the MountService. 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 925af0b916f850486cff4797355bf9e7dc3352fe00Jason parksclass MountService extends IMountService.Stub implements INativeDaemonConnectorCallbacks { 935af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 94b104340496e3a531e26c8f428c808eca0e039f50San Mehat private static final boolean LOCAL_LOGD = false; 958a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu private static final boolean DEBUG_UNMOUNT = false; 968a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu private static final boolean DEBUG_EVENTS = false; 97b7db2726e91f1d9480359d0f83b9cb7769906b34Kenny Root private static final boolean DEBUG_OBB = false; 9802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String TAG = "MountService"; 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 101305bcbf0c961840c4505770d084a1caacc074dbbKenny Root private static final String VOLD_TAG = "VoldConnector"; 102305bcbf0c961840c4505770d084a1caacc074dbbKenny Root 103cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root /** Maximum number of ASEC containers allowed to be mounted. */ 104cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root private static final int MAX_CONTAINERS = 250; 105cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root 1064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Internal vold volume state constants 1084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 1097fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat class VolumeState { 1107fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Init = -1; 1117fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int NoMedia = 0; 1127fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Idle = 1; 1137fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Pending = 2; 1147fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Checking = 3; 1157fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Mounted = 4; 1167fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Unmounting = 5; 1177fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Formatting = 6; 1187fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Shared = 7; 1197fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int SharedMnt = 8; 1207fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 1217fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 1224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Internal vold response code constants 1244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 12522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat class VoldResponseCode { 1264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 100 series - Requestion action was initiated; expect another reply 1284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * before proceeding with a new command. 1294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 13022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeListResult = 110; 13122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int AsecListResult = 111; 132c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat public static final int StorageUsersListResult = 112; 13322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 200 series - Requestion action has been successfully completed. 1364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 1374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int ShareStatusResult = 210; 13822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int AsecPathResult = 211; 1394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int ShareEnabledResult = 212; 14022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 400 series - Command was accepted, but the requested action 1434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * did not take place. 1444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 1454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedNoMedia = 401; 1464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedMediaBlank = 402; 1474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedMediaCorrupt = 403; 1484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedVolNotMounted = 404; 149d970998b0d489774ad1c5b94b47d233912f00214San Mehat public static final int OpFailedStorageBusy = 405; 1502d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat public static final int OpFailedStorageNotFound = 406; 1514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 600 series - Unsolicited broadcasts. 1544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 15522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeStateChange = 605; 15622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeDiskInserted = 630; 15722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeDiskRemoved = 631; 15822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeBadRemoval = 632; 15922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 16022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private Context mContext; 1624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private NativeDaemonConnector mConnector; 1632f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood private final ArrayList<StorageVolume> mVolumes = new ArrayList<StorageVolume>(); 1642f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood private StorageVolume mPrimaryVolume; 1657fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood private final HashMap<String, String> mVolumeStates = new HashMap<String, String>(); 166a5250c93928e256738125b265e10c96c3575597eMike Lockwood private final HashMap<String, StorageVolume> mVolumeMap = new HashMap<String, StorageVolume>(); 1677fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood private String mExternalStoragePath; 1684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private PackageManagerService mPms; 1694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private boolean mUmsEnabling; 170ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood private boolean mUmsAvailable = false; 1710eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Used as a lock for methods that register/unregister listeners. 1720eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu final private ArrayList<MountServiceBinderListener> mListeners = 1730eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu new ArrayList<MountServiceBinderListener>(); 1746a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private boolean mBooted = false; 1756a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private boolean mReady = false; 1766a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private boolean mSendUmsConnectedOnBoot = false; 17703559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood // true if we should fake MEDIA_MOUNTED state for external storage 17803559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood private boolean mEmulateExternalStorage = false; 179fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapu 1806cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat /** 1816cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat * Private hash of currently mounted secure containers. 1820eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * Used as a lock in methods to manipulate secure containers. 1836cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat */ 1840eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu final private HashSet<String> mAsecMountSet = new HashSet<String>(); 1856cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 18602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root /** 1873b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * The size of the crypto algorithm key in bits for OBB files. Currently 1883b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * Twofish is used which takes 128-bit keys. 1893b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root */ 1903b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128; 1913b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 1923b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root /** 1933b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * The number of times to run SHA1 in the PBKDF2 function for OBB files. 1943b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * 1024 is reasonably secure and not too slow. 1953b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root */ 1963b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root private static final int PBKDF2_HASH_ROUNDS = 1024; 1973b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 1983b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root /** 199a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * Mounted OBB tracking information. Used to track the current state of all 200a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * OBBs. 201a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root */ 202735de3b38abbd6564082a819377673ee593744a6Kenny Root final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>(); 203a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>(); 204a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 205a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class ObbState implements IBinder.DeathRecipient { 206af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root public ObbState(String filename, int callerUid, IObbActionListener token, int nonce) 207735de3b38abbd6564082a819377673ee593744a6Kenny Root throws RemoteException { 208a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root this.filename = filename; 209a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root this.callerUid = callerUid; 210af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root this.token = token; 211af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root this.nonce = nonce; 212a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 213a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 214a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // OBB source filename 215af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root String filename; 216a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 217a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Binder.callingUid() 21805105f7abe02b2dff91d6260b3628c8b97816babKenny Root final public int callerUid; 219a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 220af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Token of remote Binder caller 221af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IObbActionListener token; 222af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 223af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Identifier to pass back to the token 224af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final int nonce; 225a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 226735de3b38abbd6564082a819377673ee593744a6Kenny Root public IBinder getBinder() { 227735de3b38abbd6564082a819377673ee593744a6Kenny Root return token.asBinder(); 228735de3b38abbd6564082a819377673ee593744a6Kenny Root } 229735de3b38abbd6564082a819377673ee593744a6Kenny Root 230a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 231a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void binderDied() { 232a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbAction action = new UnmountObbAction(this, true); 233a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 234735de3b38abbd6564082a819377673ee593744a6Kenny Root } 235a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2365919ac6b4188285324646772501ef4b97b353cf4Kenny Root public void link() throws RemoteException { 2375919ac6b4188285324646772501ef4b97b353cf4Kenny Root getBinder().linkToDeath(this, 0); 2385919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 2395919ac6b4188285324646772501ef4b97b353cf4Kenny Root 2405919ac6b4188285324646772501ef4b97b353cf4Kenny Root public void unlink() { 241735de3b38abbd6564082a819377673ee593744a6Kenny Root getBinder().unlinkToDeath(this, 0); 242a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 24338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 24438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root @Override 24538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root public String toString() { 24638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root StringBuilder sb = new StringBuilder("ObbState{"); 24738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append("filename="); 24838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(filename); 24938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(",token="); 25038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(token.toString()); 25138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(",callerUid="); 25238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(callerUid); 25338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append('}'); 25438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return sb.toString(); 25538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 256a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 257a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 258a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // OBB Action Handler 259a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private ObbActionHandler mObbActionHandler; 260a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 261a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // OBB action handler messages 262a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_RUN_ACTION = 1; 263a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_BOUND = 2; 264a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_UNBIND = 3; 265a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_RECONNECT = 4; 266af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private static final int OBB_FLUSH_MOUNT_STATE = 5; 267a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 268a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root /* 269a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * Default Container Service information 27002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root */ 271a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName( 272a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService"); 273a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 274a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection(); 275a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 276a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class DefaultContainerConnection implements ServiceConnection { 277a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void onServiceConnected(ComponentName name, IBinder service) { 278a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 279a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "onServiceConnected"); 280a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service); 281a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs)); 282a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 283a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 284a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void onServiceDisconnected(ComponentName name) { 285a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 286a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "onServiceDisconnected"); 287a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 288a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root }; 289a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 290a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Used in the ObbActionHandler 291a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private IMediaContainerService mContainerService = null; 29202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 29302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root // Handler messages 294c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_PM_UPDATE = 1; 295c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_PM_DONE = 2; 296c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_MS = 3; 297c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int RETRY_UNMOUNT_DELAY = 30; // in ms 298c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int MAX_UNMOUNT_RETRIES = 4; 299c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 300c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu class UnmountCallBack { 30105105f7abe02b2dff91d6260b3628c8b97816babKenny Root final String path; 30205105f7abe02b2dff91d6260b3628c8b97816babKenny Root final boolean force; 303c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu int retries; 304c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 305c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack(String path, boolean force) { 306c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu retries = 0; 307c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu this.path = path; 308c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu this.force = force; 309c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 3100eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3110eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu void handleFinished() { 312a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path); 3130eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doUnmountVolume(path, true); 3140eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 3150eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 3160eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3170eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu class UmsEnableCallBack extends UnmountCallBack { 31805105f7abe02b2dff91d6260b3628c8b97816babKenny Root final String method; 3190eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3200eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu UmsEnableCallBack(String path, String method, boolean force) { 3210eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu super(path, force); 3220eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu this.method = method; 3230eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 3240eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3250eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu @Override 3260eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu void handleFinished() { 3270eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu super.handleFinished(); 3280eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doShareUnshareVolume(path, method, true); 3290eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 330c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 331c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 3326ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu class ShutdownCallBack extends UnmountCallBack { 3336ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu IMountShutdownObserver observer; 3346ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu ShutdownCallBack(String path, IMountShutdownObserver observer) { 3356ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu super(path, true); 3366ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu this.observer = observer; 3376ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3386ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3396ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu @Override 3406ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu void handleFinished() { 3416ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int ret = doUnmountVolume(path, true); 3426ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (observer != null) { 3436ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu try { 3446ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu observer.onShutDownComplete(ret); 3456ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } catch (RemoteException e) { 346a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "RemoteException when shutting down"); 3476ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3486ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3496ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3506ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3516ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3525f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler class MountServiceHandler extends Handler { 353c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>(); 354e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu boolean mUpdatingStatus = false; 3556ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3565f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler MountServiceHandler(Looper l) { 3575f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler super(l); 3585f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler } 3595f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler 3605af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 361c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu public void handleMessage(Message msg) { 362c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu switch (msg.what) { 363c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_PM_UPDATE: { 364a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_UPDATE"); 365c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = (UnmountCallBack) msg.obj; 366c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu mForceUnmounts.add(ucb); 367a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, " registered = " + mUpdatingStatus); 3686ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Register only if needed. 369e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu if (!mUpdatingStatus) { 370a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Updating external media status on PackageManager"); 371e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mUpdatingStatus = true; 372e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(false, true); 373c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 374c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 375c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 376c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_PM_DONE: { 377a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_DONE"); 378a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Updated status. Processing requests"); 379e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mUpdatingStatus = false; 3806ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int size = mForceUnmounts.size(); 3816ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int sizeArr[] = new int[size]; 3826ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int sizeArrN = 0; 3837af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Kill processes holding references first 3847af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ActivityManagerService ams = (ActivityManagerService) 3857af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ServiceManager.getService("activity"); 3866ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu for (int i = 0; i < size; i++) { 3876ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu UnmountCallBack ucb = mForceUnmounts.get(i); 3886ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu String path = ucb.path; 3896ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu boolean done = false; 3906ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (!ucb.force) { 391c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu done = true; 392c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } else { 3936ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int pids[] = getStorageUsers(path); 3946ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (pids == null || pids.length == 0) { 3956ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu done = true; 3966ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } else { 3976ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Eliminate system process here? 398648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn ams.killPids(pids, "unmount media", true); 3997af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Confirm if file references have been freed. 4007af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu pids = getStorageUsers(path); 4017af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu if (pids == null || pids.length == 0) { 4027af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu done = true; 403c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 404c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 405c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 4067af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) { 4077af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Retry again 4087af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu Slog.i(TAG, "Retrying to kill storage users again"); 4097af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.sendMessageDelayed( 4107af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.obtainMessage(H_UNMOUNT_PM_DONE, 4117af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ucb.retries++), 4127af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu RETRY_UNMOUNT_DELAY); 413c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } else { 4146ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (ucb.retries >= MAX_UNMOUNT_RETRIES) { 4157af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu Slog.i(TAG, "Failed to unmount media inspite of " + 4167af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu MAX_UNMOUNT_RETRIES + " retries. Forcibly killing processes now"); 4176ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 4187af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu sizeArr[sizeArrN++] = i; 4197af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS, 4207af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ucb)); 421c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 422c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 4236ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Remove already processed elements from list. 4246ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu for (int i = (sizeArrN-1); i >= 0; i--) { 4256ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu mForceUnmounts.remove(sizeArr[i]); 4266ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 427c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 428c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 429c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_MS : { 430a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_MS"); 431c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = (UnmountCallBack) msg.obj; 4320eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu ucb.handleFinished(); 433c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 434c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 435c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 436c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 437c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu }; 4385f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler final private HandlerThread mHandlerThread; 4395f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler final private Handler mHandler; 440c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 441207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void waitForReady() { 442207e538350665cea00e1aa70b8094beca4a34e45San Mehat while (mReady == false) { 443207e538350665cea00e1aa70b8094beca4a34e45San Mehat for (int retries = 5; retries > 0; retries--) { 444207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (mReady) { 445207e538350665cea00e1aa70b8094beca4a34e45San Mehat return; 446207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 447207e538350665cea00e1aa70b8094beca4a34e45San Mehat SystemClock.sleep(1000); 448207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 449a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Waiting too long for mReady!"); 450207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 4511f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 45202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 453207e538350665cea00e1aa70b8094beca4a34e45San Mehat private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 4545af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onReceive(Context context, Intent intent) { 45691c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat String action = intent.getAction(); 45791c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 45891c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { 459207e538350665cea00e1aa70b8094beca4a34e45San Mehat mBooted = true; 46022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 461c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen /* 462c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * In the simulator, we need to broadcast a volume mounted event 463c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * to make the media scanner run. 464c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen */ 465c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen if ("simulator".equals(SystemProperties.get("ro.product.device"))) { 46684338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood notifyVolumeStateChange(null, "/sdcard", VolumeState.NoMedia, 46784338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood VolumeState.Mounted); 468c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen return; 469c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen } 470fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat new Thread() { 4715af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 472fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat public void run() { 473fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat try { 47484338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood // it is not safe to call vold with mVolumeStates locked 47584338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood // so we make a copy of the paths and states and process them 47684338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood // outside the lock 47784338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood String[] paths, states; 47884338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood int count; 4797fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood synchronized (mVolumeStates) { 48084338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood Set<String> keys = mVolumeStates.keySet(); 48184338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood count = keys.size(); 48284338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood paths = (String[])keys.toArray(new String[count]); 48384338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood states = new String[count]; 48484338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood for (int i = 0; i < count; i++) { 48584338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood states[i] = mVolumeStates.get(paths[i]); 48684338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood } 48784338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood } 48884338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood 48984338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood for (int i = 0; i < count; i++) { 49084338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood String path = paths[i]; 49184338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood String state = states[i]; 49284338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood 49384338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood if (state.equals(Environment.MEDIA_UNMOUNTED)) { 49484338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood int rc = doMountVolume(path); 49584338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood if (rc != StorageResultCode.OperationSucceeded) { 49684338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood Slog.e(TAG, String.format("Boot-time mount failed (%d)", 49784338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood rc)); 4987fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 49984338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood } else if (state.equals(Environment.MEDIA_SHARED)) { 50084338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood /* 50184338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood * Bootstrap UMS enabled state since vold indicates 50284338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood * the volume is shared (runtime restart while ums enabled) 50384338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood */ 50484338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood notifyVolumeStateChange(null, path, VolumeState.NoMedia, 50584338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood VolumeState.Shared); 506fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } 507fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } 5086a254403235196692b1769d2fe281b0852c0cc25San Mehat 50980e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood /* notify external storage has mounted to trigger media scanner */ 51080e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood if (mEmulateExternalStorage) { 51180e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood notifyVolumeStateChange(null, 51280e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood Environment.getExternalStorageDirectory().getPath(), 51380e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood VolumeState.NoMedia, VolumeState.Mounted); 51480e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood } 51580e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood 5166a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat /* 5176a254403235196692b1769d2fe281b0852c0cc25San Mehat * If UMS was connected on boot, send the connected event 5186a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat * now that we're up. 5196a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat */ 5206a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat if (mSendUmsConnectedOnBoot) { 5216a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat sendUmsIntent(true); 5226a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat mSendUmsConnectedOnBoot = false; 5236a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } 524fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } catch (Exception ex) { 525a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Boot-time mount exception", ex); 526fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } 527207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 528fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat }.start(); 529ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood } else if (action.equals(UsbManager.ACTION_USB_STATE)) { 530ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood boolean available = (intent.getBooleanExtra(UsbManager.USB_CONNECTED, false) && 531ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood intent.getBooleanExtra(UsbManager.USB_FUNCTION_MASS_STORAGE, false)); 532ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood notifyShareAvailabilityChange(available); 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 5364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private final class MountServiceBinderListener implements IBinder.DeathRecipient { 5374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final IMountServiceListener mListener; 53891c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 5394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener(IMountServiceListener listener) { 5404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListener = listener; 54102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 54291c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 54391c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 5444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void binderDied() { 545a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!"); 546a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root synchronized (mListeners) { 5474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(this); 5484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListener.asBinder().unlinkToDeath(this, 0); 54991c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 55091c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 55191c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 55291c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 5530eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private void doShareUnshareVolume(String path, String method, boolean enable) { 5544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat // TODO: Add support for multiple share methods 5554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!method.equals("ums")) { 5564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new IllegalArgumentException(String.format("Method %s not supported", method)); 5577fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 5604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(String.format( 5614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat "volume %sshare %s %s", (enable ? "" : "un"), path, method)); 5624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 563a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to share/unshare", e); 56422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 567207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void updatePublicVolumeState(String path, String state) { 5687fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String oldState; 5697fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood synchronized(mVolumeStates) { 5707fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood oldState = mVolumeStates.put(path, state); 5717fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 5727fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state.equals(oldState)) { 5737fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.w(TAG, String.format("Duplicate state transition (%s -> %s) for %s", 5747fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood state, state, path)); 575b104340496e3a531e26c8f428c808eca0e039f50San Mehat return; 576b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 577af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 5787fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.d(TAG, "volume state changed for " + path + " (" + oldState + " -> " + state + ")"); 5797fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 5807fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (path.equals(mExternalStoragePath)) { 5817fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood // Update state on PackageManager, but only of real events 5827fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (!mEmulateExternalStorage) { 5837fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (Environment.MEDIA_UNMOUNTED.equals(state)) { 5847fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood mPms.updateExternalMediaStatus(false, false); 5857fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 5867fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood /* 5877fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * Some OBBs might have been unmounted when this volume was 5887fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * unmounted, so send a message to the handler to let it know to 5897fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * remove those from the list of mounted OBBS. 5907fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood */ 5917fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage( 5927fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood OBB_FLUSH_MOUNT_STATE, path)); 5937fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } else if (Environment.MEDIA_MOUNTED.equals(state)) { 5947fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood mPms.updateExternalMediaStatus(true, false); 5957fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 59603559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood } 5978a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 5984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 5994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for (int i = mListeners.size() -1; i >= 0; i--) { 6004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = mListeners.get(i); 6014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 602b104340496e3a531e26c8f428c808eca0e039f50San Mehat bl.mListener.onStorageStateChanged(path, oldState, state); 6034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 604a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener dead"); 6054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(i); 6064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 607a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener failed", ex); 6084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 61322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat /** 61422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * 61522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * Callback from NativeDaemonConnector 61622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat */ 61722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public void onDaemonConnected() { 6185b77dab23469273d41f9c530d947ac055765e6eaSan Mehat /* 6195b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * Since we'll be calling back into the NativeDaemonConnector, 6205b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * we need to do our work in a new thread. 6215b77dab23469273d41f9c530d947ac055765e6eaSan Mehat */ 6227fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat new Thread() { 6235af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 6247fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public void run() { 6255b77dab23469273d41f9c530d947ac055765e6eaSan Mehat /** 6265b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * Determine media state and UMS detection status 6275b77dab23469273d41f9c530d947ac055765e6eaSan Mehat */ 6287fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat try { 6295b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String[] vols = mConnector.doListCommand( 6304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat "volume list", VoldResponseCode.VolumeListResult); 6315b77dab23469273d41f9c530d947ac055765e6eaSan Mehat for (String volstr : vols) { 6325b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String[] tok = volstr.split(" "); 6335b77dab23469273d41f9c530d947ac055765e6eaSan Mehat // FMT: <label> <mountpoint> <state> 6347fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String path = tok[1]; 6357fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String state = Environment.MEDIA_REMOVED; 6367fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 6375b77dab23469273d41f9c530d947ac055765e6eaSan Mehat int st = Integer.parseInt(tok[2]); 6385b77dab23469273d41f9c530d947ac055765e6eaSan Mehat if (st == VolumeState.NoMedia) { 6395b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_REMOVED; 6405b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Idle) { 641207e538350665cea00e1aa70b8094beca4a34e45San Mehat state = Environment.MEDIA_UNMOUNTED; 6425b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Mounted) { 6435b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_MOUNTED; 644a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Media already mounted on daemon connection"); 6455b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Shared) { 6465b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_SHARED; 647a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Media shared on daemon connection"); 6485b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else { 6495b77dab23469273d41f9c530d947ac055765e6eaSan Mehat throw new Exception(String.format("Unexpected state %d", st)); 6507fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6517fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 6527fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state != null) { 6537fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state); 6547fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood updatePublicVolumeState(path, state); 6557fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 656c2a39471642e31d7350910612e40d078b825173aSan Mehat } 6575b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } catch (Exception e) { 658a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Error processing initial volume state", e); 6597fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood updatePublicVolumeState(mExternalStoragePath, Environment.MEDIA_REMOVED); 6607fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6617fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 662207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 6639ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks * Now that we've done our initialization, release 664207e538350665cea00e1aa70b8094beca4a34e45San Mehat * the hounds! 665207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 666207e538350665cea00e1aa70b8094beca4a34e45San Mehat mReady = true; 6677fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6687fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat }.start(); 6697fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6707fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 67122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat /** 67222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * Callback from NativeDaemonConnector 67322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat */ 67422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public boolean onEvent(int code, String raw, String[] cooked) { 6758a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (DEBUG_EVENTS) { 6768a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu StringBuilder builder = new StringBuilder(); 6778a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append("onEvent::"); 6788a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" raw= " + raw); 6798a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (cooked != null) { 6808a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" cooked = " ); 6818a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu for (String str : cooked) { 6828a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" " + str); 6838a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 6848a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 685a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, builder.toString()); 6868a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 68722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat if (code == VoldResponseCode.VolumeStateChange) { 6884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 6894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * One of the volumes we're managing has changed state. 6904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Format: "NNN Volume <label> <path> state changed 6914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * from <old_#> (<old_str>) to <new_#> (<new_str>)" 6924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 69322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat notifyVolumeStateChange( 69422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat cooked[2], cooked[3], Integer.parseInt(cooked[7]), 69522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat Integer.parseInt(cooked[10])); 6964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if ((code == VoldResponseCode.VolumeDiskInserted) || 6974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat (code == VoldResponseCode.VolumeDiskRemoved) || 6984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat (code == VoldResponseCode.VolumeBadRemoval)) { 69922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>) 70022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>) 70122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>) 702a5250c93928e256738125b265e10c96c3575597eMike Lockwood String action = null; 7034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final String label = cooked[2]; 7044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final String path = cooked[3]; 7054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int major = -1; 7064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int minor = -1; 7074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 7084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 7094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String devComp = cooked[6].substring(1, cooked[6].length() -1); 7104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String[] devTok = devComp.split(":"); 7114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat major = Integer.parseInt(devTok[0]); 7124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat minor = Integer.parseInt(devTok[1]); 7134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 714a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to parse major/minor", ex); 7154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 7174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (code == VoldResponseCode.VolumeDiskInserted) { 7184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat new Thread() { 7195af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 7204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void run() { 7214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 7224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int rc; 723b104340496e3a531e26c8f428c808eca0e039f50San Mehat if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { 724a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, String.format("Insertion mount failed (%d)", rc)); 7254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 727a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Failed to mount media on insertion", ex); 7284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat }.start(); 7314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (code == VoldResponseCode.VolumeDiskRemoved) { 7324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 7334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * This event gets trumped if we're already in BAD_REMOVAL state 7344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 7354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) { 7364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return true; 7374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 739a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first"); 7404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 741a5250c93928e256738125b265e10c96c3575597eMike Lockwood sendStorageIntent(Environment.MEDIA_UNMOUNTED, path); 7424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 743a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed"); 7444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_REMOVED); 745a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_REMOVED; 7464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (code == VoldResponseCode.VolumeBadRemoval) { 747a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first"); 7484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 7494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 750a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_UNMOUNTED; 7514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 752a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal"); 7534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL); 754a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_BAD_REMOVAL; 7554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else { 756a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Unknown code {%d}", code)); 7574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 758a5250c93928e256738125b265e10c96c3575597eMike Lockwood 759a5250c93928e256738125b265e10c96c3575597eMike Lockwood if (action != null) { 760a5250c93928e256738125b265e10c96c3575597eMike Lockwood sendStorageIntent(action, path); 761a5250c93928e256738125b265e10c96c3575597eMike Lockwood } 76222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else { 76322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat return false; 76422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 7654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 7665f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler return true; 76722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 76822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 769207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void notifyVolumeStateChange(String label, String path, int oldState, int newState) { 7704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String vs = getVolumeState(path); 771a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChanged::" + vs); 7724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 773a5250c93928e256738125b265e10c96c3575597eMike Lockwood String action = null; 7747fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 775bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood if (oldState == VolumeState.Shared && newState != oldState) { 776a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent"); 777a5250c93928e256738125b265e10c96c3575597eMike Lockwood sendStorageIntent(Intent.ACTION_MEDIA_UNSHARED, path); 778bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood } 779bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood 7807fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat if (newState == VolumeState.Init) { 7817fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.NoMedia) { 7827fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat // NoMedia is handled via Disk Remove events 7837fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Idle) { 7845fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat /* 7855fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or 7865fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat * if we're in the process of enabling UMS 7875fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat */ 7884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!vs.equals( 7894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Environment.MEDIA_BAD_REMOVAL) && !vs.equals( 7904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Environment.MEDIA_NOFS) && !vs.equals( 7910eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) { 792a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable"); 7934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 794a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_UNMOUNTED; 7957fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 7967fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Pending) { 7977fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Checking) { 798a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking"); 7994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_CHECKING); 800a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_CHECKING; 8017fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Mounted) { 802a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted"); 8034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_MOUNTED); 804a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_MOUNTED; 8057fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Unmounting) { 806a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_EJECT; 8077fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Formatting) { 8087fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Shared) { 809a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted"); 8104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 8114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 812a5250c93928e256738125b265e10c96c3575597eMike Lockwood sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, path); 8134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 814a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared"); 8154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_SHARED); 816a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_SHARED; 817a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent"); 8187fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.SharedMnt) { 819a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Live shared mounts not supported yet!"); 8204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return; 8217fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else { 822a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Unhandled VolumeState {" + newState + "}"); 8237fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 8247fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 825a5250c93928e256738125b265e10c96c3575597eMike Lockwood if (action != null) { 826a5250c93928e256738125b265e10c96c3575597eMike Lockwood sendStorageIntent(action, path); 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 830207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doMountVolume(String path) { 831b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 832207e538350665cea00e1aa70b8094beca4a34e45San Mehat 833a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path); 834207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 835207e538350665cea00e1aa70b8094beca4a34e45San Mehat mConnector.doCommand(String.format("volume mount %s", path)); 836207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 837207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 838207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Mount failed for some reason 839207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 840a5250c93928e256738125b265e10c96c3575597eMike Lockwood String action = null; 841207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 842207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedNoMedia) { 843207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 844207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Attempt to mount but no media inserted 845207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 846b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedNoMedia; 847207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaBlank) { 848a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs"); 849207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 850207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Media is blank or does not contain a supported filesystem 851207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 852207e538350665cea00e1aa70b8094beca4a34e45San Mehat updatePublicVolumeState(path, Environment.MEDIA_NOFS); 853a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_NOFS; 854b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedMediaBlank; 855207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { 856a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state media corrupt"); 857207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 858207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Volume consistency check failed 859207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 860207e538350665cea00e1aa70b8094beca4a34e45San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE); 861a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_UNMOUNTABLE; 862b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedMediaCorrupt; 863207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 864b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 865207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 866207e538350665cea00e1aa70b8094beca4a34e45San Mehat 867207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 868207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Send broadcast intent (if required for the failure) 869207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 870a5250c93928e256738125b265e10c96c3575597eMike Lockwood if (action != null) { 871a5250c93928e256738125b265e10c96c3575597eMike Lockwood sendStorageIntent(action, path); 872207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 873207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 874207e538350665cea00e1aa70b8094beca4a34e45San Mehat 875207e538350665cea00e1aa70b8094beca4a34e45San Mehat return rc; 876207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 877207e538350665cea00e1aa70b8094beca4a34e45San Mehat 878c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu /* 879c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * If force is not set, we do not unmount if there are 880c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * processes holding references to the volume about to be unmounted. 881c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * If force is set, all the processes holding references need to be 882c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * killed via the ActivityManager before actually unmounting the volume. 883c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * This might even take a while and might be retried after timed delays 884c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * to make sure we dont end up in an instable state and kill some core 885c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * processes. 886c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu */ 887d970998b0d489774ad1c5b94b47d233912f00214San Mehat private int doUnmountVolume(String path, boolean force) { 88859443a673a736978361dc341f41ce4e9dae053a0San Mehat if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) { 889207e538350665cea00e1aa70b8094beca4a34e45San Mehat return VoldResponseCode.OpFailedVolNotMounted; 890207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 891aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 892aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 893aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 894aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 895aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 896aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 897aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 898aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 899aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 900c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu // Redundant probably. But no harm in updating state again. 901e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(false, false); 902207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 903d970998b0d489774ad1c5b94b47d233912f00214San Mehat mConnector.doCommand(String.format( 904d970998b0d489774ad1c5b94b47d233912f00214San Mehat "volume unmount %s%s", path, (force ? " force" : ""))); 905e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu // We unmounted the volume. None of the asec containers are available now. 906e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu synchronized (mAsecMountSet) { 907e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mAsecMountSet.clear(); 908e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu } 909b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationSucceeded; 910207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 911207e538350665cea00e1aa70b8094beca4a34e45San Mehat // Don't worry about mismatch in PackageManager since the 912207e538350665cea00e1aa70b8094beca4a34e45San Mehat // call back will handle the status changes any way. 913207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 914207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedVolNotMounted) { 915a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageNotMounted; 916d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else if (code == VoldResponseCode.OpFailedStorageBusy) { 917d970998b0d489774ad1c5b94b47d233912f00214San Mehat return StorageResultCode.OperationFailedStorageBusy; 918207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 919b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedInternalError; 920207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 921207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 922207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 923207e538350665cea00e1aa70b8094beca4a34e45San Mehat 924207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doFormatVolume(String path) { 925207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 926207e538350665cea00e1aa70b8094beca4a34e45San Mehat String cmd = String.format("volume format %s", path); 927207e538350665cea00e1aa70b8094beca4a34e45San Mehat mConnector.doCommand(cmd); 928b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationSucceeded; 929207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 930207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 931207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedNoMedia) { 932b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedNoMedia; 933207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { 934b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedMediaCorrupt; 935207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 936b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedInternalError; 937207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 938207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 939207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 940207e538350665cea00e1aa70b8094beca4a34e45San Mehat 941b104340496e3a531e26c8f428c808eca0e039f50San Mehat private boolean doGetVolumeShared(String path, String method) { 942b104340496e3a531e26c8f428c808eca0e039f50San Mehat String cmd = String.format("volume shared %s %s", path, method); 943a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root ArrayList<String> rsp; 944a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root 945a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root try { 946a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root rsp = mConnector.doCommand(cmd); 947a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } catch (NativeDaemonConnectorException ex) { 948a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root Slog.e(TAG, "Failed to read response to volume shared " + path + " " + method); 949a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return false; 950a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } 951b104340496e3a531e26c8f428c808eca0e039f50San Mehat 952b104340496e3a531e26c8f428c808eca0e039f50San Mehat for (String line : rsp) { 953a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root String[] tok = line.split(" "); 954a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root if (tok.length < 3) { 955a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root Slog.e(TAG, "Malformed response to volume shared " + path + " " + method + " command"); 956a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return false; 957a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } 958a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root 959b104340496e3a531e26c8f428c808eca0e039f50San Mehat int code; 960b104340496e3a531e26c8f428c808eca0e039f50San Mehat try { 961b104340496e3a531e26c8f428c808eca0e039f50San Mehat code = Integer.parseInt(tok[0]); 962b104340496e3a531e26c8f428c808eca0e039f50San Mehat } catch (NumberFormatException nfe) { 963a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Error parsing code %s", tok[0])); 964b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 965b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 966b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (code == VoldResponseCode.ShareEnabledResult) { 967a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return "enabled".equals(tok[2]); 968b104340496e3a531e26c8f428c808eca0e039f50San Mehat } else { 969a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Unexpected response code %d", code)); 970b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 971b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 972b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 973a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Got an empty response"); 974b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 975b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 976b104340496e3a531e26c8f428c808eca0e039f50San Mehat 977ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood private void notifyShareAvailabilityChange(final boolean avail) { 9784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 979ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood mUmsAvailable = avail; 9804270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for (int i = mListeners.size() -1; i >= 0; i--) { 9814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = mListeners.get(i); 9821f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat try { 983b104340496e3a531e26c8f428c808eca0e039f50San Mehat bl.mListener.onUsbMassStorageConnectionChanged(avail); 9844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 985a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener dead"); 9864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(i); 9871f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } catch (Exception ex) { 988a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener failed", ex); 9891f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 9901f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 9914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 9927fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 993207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (mBooted == true) { 9946a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat sendUmsIntent(avail); 9956a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } else { 9966a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat mSendUmsConnectedOnBoot = avail; 9971f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 9982fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat 9992fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat final String path = Environment.getExternalStorageDirectory().getPath(); 10002fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat if (avail == false && getVolumeState(path).equals(Environment.MEDIA_SHARED)) { 10012fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat /* 10022fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat * USB mass storage disconnected while enabled 10032fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat */ 10042fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat new Thread() { 10055af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 10062fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat public void run() { 10072fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat try { 10082fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat int rc; 1009a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Disabling UMS after cable disconnect"); 10102fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat doShareUnshareVolume(path, "ums", false); 10112fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { 1012a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format( 10132fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat "Failed to remount {%s} on UMS enabled-disconnect (%d)", 10142fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat path, rc)); 10152fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 10162fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } catch (Exception ex) { 1017a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Failed to mount media on UMS enabled-disconnect", ex); 10182fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 10192fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 10202fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat }.start(); 10212fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1024a5250c93928e256738125b265e10c96c3575597eMike Lockwood private void sendStorageIntent(String action, String path) { 1025a5250c93928e256738125b265e10c96c3575597eMike Lockwood Intent intent = new Intent(action, Uri.parse("file://" + path)); 1026a5250c93928e256738125b265e10c96c3575597eMike Lockwood // add StorageVolume extra 1027a5250c93928e256738125b265e10c96c3575597eMike Lockwood intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mVolumeMap.get(path)); 1028a5250c93928e256738125b265e10c96c3575597eMike Lockwood Slog.d(TAG, "sendStorageIntent " + intent); 1029a5250c93928e256738125b265e10c96c3575597eMike Lockwood mContext.sendBroadcast(intent); 1030a5250c93928e256738125b265e10c96c3575597eMike Lockwood } 1031a5250c93928e256738125b265e10c96c3575597eMike Lockwood 10326a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private void sendUmsIntent(boolean c) { 10336a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat mContext.sendBroadcast( 10346a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat new Intent((c ? Intent.ACTION_UMS_CONNECTED : Intent.ACTION_UMS_DISCONNECTED))); 10356a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } 10366a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat 1037207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void validatePermission(String perm) { 10384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) { 10394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new SecurityException(String.format("Requires %s permission", perm)); 10404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 10417fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 10427fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 10432f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood // Storage list XML tags 10442f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood private static final String TAG_STORAGE_LIST = "StorageList"; 10452f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood private static final String TAG_STORAGE = "storage"; 10462f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 10472f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood private void readStorageList(Resources resources) { 10482f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood int id = com.android.internal.R.xml.storage_list; 10492f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood XmlResourceParser parser = resources.getXml(id); 10502f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood AttributeSet attrs = Xml.asAttributeSet(parser); 10512f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 10522f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood try { 10532f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood XmlUtils.beginDocument(parser, TAG_STORAGE_LIST); 10542f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood while (true) { 10552f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood XmlUtils.nextElement(parser); 10562f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 10572f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood String element = parser.getName(); 10582f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (element == null) break; 10592f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 10602f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (TAG_STORAGE.equals(element)) { 10612f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood TypedArray a = resources.obtainAttributes(attrs, 10622f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage); 10632f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 10642f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood CharSequence path = a.getText( 10652f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_mountPoint); 10662f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood CharSequence description = a.getText( 10672f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_storageDescription); 10682f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood boolean primary = a.getBoolean( 10692f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_primary, false); 10702f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood boolean removable = a.getBoolean( 10712f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_removable, false); 10722f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood boolean emulated = a.getBoolean( 10732f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_emulated, false); 10742f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood int mtpReserve = a.getInt( 10752f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_mtpReserve, 0); 10768e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood boolean allowMassStorage = a.getBoolean( 10778e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood com.android.internal.R.styleable.Storage_allowMassStorage, false); 10782f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 10792f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood Slog.d(TAG, "got storage path: " + path + " description: " + description + 10802f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood " primary: " + primary + " removable: " + removable + 10818e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood " emulated: " + emulated + " mtpReserve: " + mtpReserve + 10828e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood " allowMassStorage: " + allowMassStorage); 10832f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (path == null || description == null) { 10842f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood Slog.e(TAG, "path or description is null in readStorageList"); 10852f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } else { 1086a5250c93928e256738125b265e10c96c3575597eMike Lockwood String pathString = path.toString(); 1087a5250c93928e256738125b265e10c96c3575597eMike Lockwood StorageVolume volume = new StorageVolume(pathString, 10888e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood description.toString(), removable, emulated, 10898e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood mtpReserve, allowMassStorage); 10902f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (primary) { 10912f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (mPrimaryVolume == null) { 10922f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood mPrimaryVolume = volume; 10932f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } else { 10942f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood Slog.e(TAG, "multiple primary volumes in storage list"); 10952f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 10962f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 10972f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (mPrimaryVolume == volume) { 10982f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood // primay volume must be first 10992f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood mVolumes.add(0, volume); 11002f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } else { 11012f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood mVolumes.add(volume); 11022f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 1103a5250c93928e256738125b265e10c96c3575597eMike Lockwood mVolumeMap.put(pathString, volume); 11042f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 11052f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood a.recycle(); 11062f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 11072f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 11082f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } catch (XmlPullParserException e) { 11092f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood throw new RuntimeException(e); 11102f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } catch (IOException e) { 11112f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood throw new RuntimeException(e); 11122f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } finally { 1113fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood // compute storage ID for each volume 1114fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood int length = mVolumes.size(); 1115fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood for (int i = 0; i < length; i++) { 1116fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood mVolumes.get(i).setStorageId(i); 1117fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood } 11182f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood parser.close(); 11192f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 11202f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 11212f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1123207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Constructs a new MountService instance 1124207e538350665cea00e1aa70b8094beca4a34e45San Mehat * 1125207e538350665cea00e1aa70b8094beca4a34e45San Mehat * @param context Binder context for this service 1126207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 1127207e538350665cea00e1aa70b8094beca4a34e45San Mehat public MountService(Context context) { 1128207e538350665cea00e1aa70b8094beca4a34e45San Mehat mContext = context; 11292f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood Resources resources = context.getResources(); 11302f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood readStorageList(resources); 11312f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 11322f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (mPrimaryVolume != null) { 11332f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood mExternalStoragePath = mPrimaryVolume.getPath(); 11342f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood mEmulateExternalStorage = mPrimaryVolume.isEmulated(); 11352f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (mEmulateExternalStorage) { 11362f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood Slog.d(TAG, "using emulated external storage"); 11372f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood mVolumeStates.put(mExternalStoragePath, Environment.MEDIA_MOUNTED); 11382f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 113903559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood } 114003559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood 1141207e538350665cea00e1aa70b8094beca4a34e45San Mehat // XXX: This will go away soon in favor of IMountServiceObserver 1142207e538350665cea00e1aa70b8094beca4a34e45San Mehat mPms = (PackageManagerService) ServiceManager.getService("package"); 1143207e538350665cea00e1aa70b8094beca4a34e45San Mehat 1144ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood IntentFilter filter = new IntentFilter(); 1145ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood filter.addAction(Intent.ACTION_BOOT_COMPLETED); 1146ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood // don't bother monitoring USB if mass storage is not supported on our primary volume 1147ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood if (mPrimaryVolume != null && mPrimaryVolume.allowMassStorage()) { 1148ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood filter.addAction(UsbManager.ACTION_USB_STATE); 1149ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood } 1150ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood mContext.registerReceiver(mBroadcastReceiver, filter, null, null); 1151207e538350665cea00e1aa70b8094beca4a34e45San Mehat 11525f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandlerThread = new HandlerThread("MountService"); 11535f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandlerThread.start(); 11545f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandler = new MountServiceHandler(mHandlerThread.getLooper()); 11555f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler 1156a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Add OBB Action Handler to MountService thread. 1157a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper()); 1158a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1159c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen /* 1160c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * Vold does not run in the simulator, so pretend the connector thread 1161c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * ran and did its thing. 1162c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen */ 1163c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen if ("simulator".equals(SystemProperties.get("ro.product.device"))) { 1164c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen mReady = true; 1165c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen mUmsEnabling = true; 1166c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen return; 1167c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen } 1168c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen 1169305bcbf0c961840c4505770d084a1caacc074dbbKenny Root /* 1170305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * Create the connection to vold with a maximum queue of twice the 1171305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * amount of containers we'd ever expect to have. This keeps an 1172305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * "asec list" from blocking a thread repeatedly. 1173305bcbf0c961840c4505770d084a1caacc074dbbKenny Root */ 1174cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG); 1175207e538350665cea00e1aa70b8094beca4a34e45San Mehat mReady = false; 1176305bcbf0c961840c4505770d084a1caacc074dbbKenny Root Thread thread = new Thread(mConnector, VOLD_TAG); 1177207e538350665cea00e1aa70b8094beca4a34e45San Mehat thread.start(); 1178207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1179207e538350665cea00e1aa70b8094beca4a34e45San Mehat 1180207e538350665cea00e1aa70b8094beca4a34e45San Mehat /** 11814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Exposed API calls below here 11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11837fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 11844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void registerListener(IMountServiceListener listener) { 11854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 11864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = new MountServiceBinderListener(listener); 11874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 11884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat listener.asBinder().linkToDeath(bl, 0); 11894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.add(bl); 11904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 1191a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to link to listener death"); 11924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 11937fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void unregisterListener(IMountServiceListener listener) { 11974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 11984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for(MountServiceBinderListener bl : mListeners) { 11994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (bl.mListener == listener) { 12004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(mListeners.indexOf(bl)); 12014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return; 12024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 12034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12076ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu public void shutdown(final IMountShutdownObserver observer) { 12084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.SHUTDOWN); 12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1210a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Shutting down"); 12117fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood synchronized (mVolumeStates) { 12127fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood for (String path : mVolumeStates.keySet()) { 12137fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String state = mVolumeStates.get(path); 12147fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 12157fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state.equals(Environment.MEDIA_SHARED)) { 12167fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood /* 12177fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * If the media is currently shared, unshare it. 12187fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * XXX: This is still dangerous!. We should not 12197fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * be rebooting at *all* if UMS is enabled, since 12207fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * the UMS host could have dirty FAT cache entries 12217fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * yet to flush. 12227fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood */ 12237fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood setUsbMassStorageEnabled(false); 12247fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } else if (state.equals(Environment.MEDIA_CHECKING)) { 12257fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood /* 12267fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * If the media is being checked, then we need to wait for 12277fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * it to complete before being able to proceed. 12287fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood */ 12297fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood // XXX: @hackbod - Should we disable the ANR timer here? 12307fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood int retries = 30; 12317fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) { 12327fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood try { 12337fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Thread.sleep(1000); 12347fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } catch (InterruptedException iex) { 12357fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.e(TAG, "Interrupted while waiting for media", iex); 12367fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood break; 12377fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 12387fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood state = Environment.getExternalStorageState(); 12397fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 12407fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (retries == 0) { 12417fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.e(TAG, "Timed out waiting for media to check"); 12427fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 12434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 12447fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 12457fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state.equals(Environment.MEDIA_MOUNTED)) { 12467fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood // Post a unmount message. 12477fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood ShutdownCallBack ucb = new ShutdownCallBack(path, observer); 12487fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb)); 12497fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } else if (observer != null) { 12507fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood /* 12517fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * Observer is waiting for onShutDownComplete when we are done. 12527fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * Since nothing will be done send notification directly so shutdown 12537fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * sequence can continue. 12547fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood */ 12557fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood try { 12567fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood observer.onShutDownComplete(StorageResultCode.OperationSucceeded); 12577fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } catch (RemoteException e) { 12587fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.w(TAG, "RemoteException when shutting down"); 12597fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 12607fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 12615d0db4d356346bee68aec9a124df70dbaa9aaed1Johan Alfven } 12621f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12650eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private boolean getUmsEnabling() { 12660eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu synchronized (mListeners) { 12670eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu return mUmsEnabling; 12680eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 12690eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 12700eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 12710eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private void setUmsEnabling(boolean enable) { 12720eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu synchronized (mListeners) { 1273fc71125104650c61ab5b04f4c943de761d58cba6Tony Wu mUmsEnabling = enable; 12740eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 12750eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 12760eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 1277b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageConnected() { 1278207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 12797fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 12800eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (getUmsEnabling()) { 1281b104340496e3a531e26c8f428c808eca0e039f50San Mehat return true; 1282b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1283ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood synchronized (mListeners) { 1284ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood return mUmsAvailable; 1285ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood } 12864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12880eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu public void setUsbMassStorageEnabled(boolean enable) { 1289207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 12900eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 12910eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 12920eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // TODO: Add support for multiple share methods 1293b104340496e3a531e26c8f428c808eca0e039f50San Mehat 12940eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 12950eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * If the volume is mounted and we're enabling then unmount it 12960eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 12970eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String path = Environment.getExternalStorageDirectory().getPath(); 12980eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String vs = getVolumeState(path); 12990eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String method = "ums"; 13000eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (enable && vs.equals(Environment.MEDIA_MOUNTED)) { 13010eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Override for isUsbMassStorageEnabled() 13020eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu setUmsEnabling(enable); 13030eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true); 13040eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb)); 13050eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Clear override 13060eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu setUmsEnabling(false); 13070eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 13080eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 13090eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * If we disabled UMS then mount the volume 13100eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 13110eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (!enable) { 13120eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doShareUnshareVolume(path, method, enable); 13130eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (doMountVolume(path) != StorageResultCode.OperationSucceeded) { 1314a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to remount " + path + 13150eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu " after disabling share method " + method); 13160eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 13170eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * Even though the mount failed, the unshare didn't so don't indicate an error. 13180eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * The mountVolume() call will have set the storage state and sent the necessary 13190eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * broadcasts. 13200eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 13210eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 13220eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 13234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1325b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageEnabled() { 1326207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1327b104340496e3a531e26c8f428c808eca0e039f50San Mehat return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums"); 13289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13299ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * @return state of the volume at the specified mount point 13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String getVolumeState(String mountPoint) { 13347fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood synchronized (mVolumeStates) { 13357fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String state = mVolumeStates.get(mountPoint); 13367fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state == null) { 13377fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume"); 13387fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood throw new IllegalArgumentException(); 13397fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 13404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 13417fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood return state; 13427fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1345e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root public boolean isExternalStorageEmulated() { 1346e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root return mEmulateExternalStorage; 1347e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root } 1348e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root 13494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int mountVolume(String path) { 13504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1352207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1353207e538350665cea00e1aa70b8094beca4a34e45San Mehat return doMountVolume(path); 13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1356c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu public void unmountVolume(String path, boolean force) { 13574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1358207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13608a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu String volState = getVolumeState(path); 1361a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path + " force = " + force); 13628a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (Environment.MEDIA_UNMOUNTED.equals(volState) || 13638a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_REMOVED.equals(volState) || 13648a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_SHARED.equals(volState) || 13658a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_UNMOUNTABLE.equals(volState)) { 13668a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // Media already unmounted or cannot be unmounted. 13678a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // TODO return valid return code when adding observer call back. 13688a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu return; 13698a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 1370c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = new UnmountCallBack(path, force); 1371c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb)); 13724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int formatVolume(String path) { 13754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); 1376207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 13779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1378207e538350665cea00e1aa70b8094beca4a34e45San Mehat return doFormatVolume(path); 13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13803697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1381ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood public int[] getStorageUsers(String path) { 1382c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1383c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat waitForReady(); 1384c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat try { 1385c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat String[] r = mConnector.doListCommand( 1386c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat String.format("storage users %s", path), 1387c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat VoldResponseCode.StorageUsersListResult); 1388c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat // FMT: <pid> <process name> 1389c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat int[] data = new int[r.length]; 1390c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat for (int i = 0; i < r.length; i++) { 1391c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat String []tok = r[i].split(" "); 1392c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat try { 1393c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat data[i] = Integer.parseInt(tok[0]); 1394c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } catch (NumberFormatException nfe) { 1395a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Error parsing pid %s", tok[0])); 1396c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return new int[0]; 1397c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1398c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1399c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return data; 1400c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } catch (NativeDaemonConnectorException e) { 1401a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to retrieve storage users list", e); 1402c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return new int[0]; 1403c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1404c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1405c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat 1406b104340496e3a531e26c8f428c808eca0e039f50San Mehat private void warnOnNotMounted() { 1407b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 1408a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "getSecureContainerList() called when storage not mounted"); 1409b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1410b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1411b104340496e3a531e26c8f428c808eca0e039f50San Mehat 14124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String[] getSecureContainerList() { 14134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 1414207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1415b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1416f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 14174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 14184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult); 14194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 14204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return new String[0]; 142102735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 14223697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 14233697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 14244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int createSecureContainer(String id, int sizeMb, String fstype, 14254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String key, int ownerUid) { 14264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_CREATE); 1427207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1428b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 14294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1430b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 14314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String cmd = String.format("asec create %s %d %s %s %d", id, sizeMb, fstype, key, ownerUid); 14324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 14334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 14344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1435b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 143602735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1437a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1438a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (rc == StorageResultCode.OperationSucceeded) { 1439a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1440a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat mAsecMountSet.add(id); 1441a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1442a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 14434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 14443697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 14453697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 14464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int finalizeSecureContainer(String id) { 14474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_CREATE); 1448b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 14494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1450b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 14514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 14524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(String.format("asec finalize %s", id)); 1453a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat /* 1454a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat * Finalization does a remount, so no need 1455a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat * to update mAsecMountSet 1456a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat */ 14574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1458b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 145902735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 14604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 14613697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 14623697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1463d970998b0d489774ad1c5b94b47d233912f00214San Mehat public int destroySecureContainer(String id, boolean force) { 14644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_DESTROY); 1465207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1466b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1467f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 1468aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 1469aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 1470aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 1471aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 1472aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 1473aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 1474aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 1475aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 1476b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 14774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1478d970998b0d489774ad1c5b94b47d233912f00214San Mehat mConnector.doCommand(String.format("asec destroy %s%s", id, (force ? " force" : ""))); 14794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1480d970998b0d489774ad1c5b94b47d233912f00214San Mehat int code = e.getCode(); 1481d970998b0d489774ad1c5b94b47d233912f00214San Mehat if (code == VoldResponseCode.OpFailedStorageBusy) { 1482d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedStorageBusy; 1483d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else { 1484d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedInternalError; 1485d970998b0d489774ad1c5b94b47d233912f00214San Mehat } 148602735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1487a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1488a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (rc == StorageResultCode.OperationSucceeded) { 1489a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1490a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (mAsecMountSet.contains(id)) { 1491a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat mAsecMountSet.remove(id); 1492a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1493a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1494a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1495a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 14964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 14973697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 14989ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 14994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int mountSecureContainer(String id, String key, int ownerUid) { 15004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 1501207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1502b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 15034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1504a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1505a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (mAsecMountSet.contains(id)) { 1506a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageMounted; 1507a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1508a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1509a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1510b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 15114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String cmd = String.format("asec mount %s %s %d", id, key, ownerUid); 15124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 15134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 15144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1515f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root int code = e.getCode(); 1516f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root if (code != VoldResponseCode.OpFailedStorageBusy) { 1517f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root rc = StorageResultCode.OperationFailedInternalError; 1518f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root } 151902735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 15206cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 15216cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (rc == StorageResultCode.OperationSucceeded) { 15226cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 15236cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat mAsecMountSet.add(id); 15246cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 15256cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 15264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 15273697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 15283697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1529d970998b0d489774ad1c5b94b47d233912f00214San Mehat public int unmountSecureContainer(String id, boolean force) { 15304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 1531207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1532b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 15334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 15346cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 15356cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (!mAsecMountSet.contains(id)) { 1536a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageNotMounted; 15376cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 15386cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 15396cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 1540aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 1541aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 1542aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 1543aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 1544aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 1545aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 1546aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 1547aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 1548b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 1549d970998b0d489774ad1c5b94b47d233912f00214San Mehat String cmd = String.format("asec unmount %s%s", id, (force ? " force" : "")); 15504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 15514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 15524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1553d970998b0d489774ad1c5b94b47d233912f00214San Mehat int code = e.getCode(); 1554d970998b0d489774ad1c5b94b47d233912f00214San Mehat if (code == VoldResponseCode.OpFailedStorageBusy) { 1555d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedStorageBusy; 1556d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else { 1557d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedInternalError; 1558d970998b0d489774ad1c5b94b47d233912f00214San Mehat } 155902735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 15606cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 15616cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (rc == StorageResultCode.OperationSucceeded) { 15626cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 15636cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat mAsecMountSet.remove(id); 15646cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 15656cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 15664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 15679dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat } 15689dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat 15696cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat public boolean isSecureContainerMounted(String id) { 15706cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 15716cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat waitForReady(); 15726cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat warnOnNotMounted(); 15736cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 15746cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 15756cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat return mAsecMountSet.contains(id); 15766cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 15776cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 15786cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 15794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int renameSecureContainer(String oldId, String newId) { 15804270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_RENAME); 1581207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1582b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 15834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1584a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 158585451ee15fdf6cae371dc3005441988c7d426401San Mehat /* 15869ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks * Because a mounted container has active internal state which cannot be 158785451ee15fdf6cae371dc3005441988c7d426401San Mehat * changed while active, we must ensure both ids are not currently mounted. 158885451ee15fdf6cae371dc3005441988c7d426401San Mehat */ 158985451ee15fdf6cae371dc3005441988c7d426401San Mehat if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) { 1590a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageMounted; 1591a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1592a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1593a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1594b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 15954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String cmd = String.format("asec rename %s %s", oldId, newId); 15964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 15974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 15984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1599b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 160002735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1601a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 16024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 160345f61040823d8c442838f75cde8760f236603daeSan Mehat } 160445f61040823d8c442838f75cde8760f236603daeSan Mehat 16054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String getSecureContainerPath(String id) { 16064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 1607207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1608b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1609f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 16102d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat try { 16112d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat ArrayList<String> rsp = mConnector.doCommand(String.format("asec path %s", id)); 16122d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat String []tok = rsp.get(0).split(" "); 161322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat int code = Integer.parseInt(tok[0]); 16142d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat if (code != VoldResponseCode.AsecPathResult) { 16152d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat throw new IllegalStateException(String.format("Unexpected response code %d", code)); 16162d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat } 16172d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat return tok[1]; 16182d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat } catch (NativeDaemonConnectorException e) { 16192d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat int code = e.getCode(); 16202d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat if (code == VoldResponseCode.OpFailedStorageNotFound) { 1621a20c8ef471666cf8b0dca91a8739ff18af1741a5Fredrik Helmer Slog.i(TAG, String.format("Container '%s' not found", id)); 1622a20c8ef471666cf8b0dca91a8739ff18af1741a5Fredrik Helmer return null; 162322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else { 16242d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat throw new IllegalStateException(String.format("Unexpected response code %d", code)); 162522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 162622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 162722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 1628e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu 1629e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu public void finishMediaUpdate() { 1630e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE); 1631e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu } 163202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1633a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) { 1634a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (callerUid == android.os.Process.SYSTEM_UID) { 1635a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return true; 1636a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1637a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 163802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (packageName == null) { 163902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return false; 164002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 164102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 164202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root final int packageUid = mPms.getPackageUid(packageName); 164302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 164402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (DEBUG_OBB) { 164502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root Slog.d(TAG, "packageName = " + packageName + ", packageUid = " + 164602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root packageUid + ", callerUid = " + callerUid); 164702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 164802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 164902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return callerUid == packageUid; 165002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 165102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 165202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root public String getMountedObbPath(String filename) { 1653af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (filename == null) { 1654af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalArgumentException("filename cannot be null"); 1655af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1656af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 165702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root waitForReady(); 165802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root warnOnNotMounted(); 165902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 166002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root try { 166102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root ArrayList<String> rsp = mConnector.doCommand(String.format("obb path %s", filename)); 166202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root String []tok = rsp.get(0).split(" "); 166302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root int code = Integer.parseInt(tok[0]); 166402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (code != VoldResponseCode.AsecPathResult) { 166502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root throw new IllegalStateException(String.format("Unexpected response code %d", code)); 166602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 166702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return tok[1]; 166802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } catch (NativeDaemonConnectorException e) { 166902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root int code = e.getCode(); 167002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (code == VoldResponseCode.OpFailedStorageNotFound) { 1671a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return null; 167202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } else { 167302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root throw new IllegalStateException(String.format("Unexpected response code %d", code)); 167402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 167502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 167602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 167702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 167802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root public boolean isObbMounted(String filename) { 1679af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (filename == null) { 1680af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalArgumentException("filename cannot be null"); 1681af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1682af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1683a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root synchronized (mObbMounts) { 1684af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return mObbPathToStateMap.containsKey(filename); 1685a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1686a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1687a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1688af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root public void mountObb(String filename, String key, IObbActionListener token, int nonce) 1689735de3b38abbd6564082a819377673ee593744a6Kenny Root throws RemoteException { 1690f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root if (filename == null) { 1691f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root throw new IllegalArgumentException("filename cannot be null"); 1692f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root } 1693f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root 1694af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (token == null) { 1695af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalArgumentException("token cannot be null"); 16962942391801b79816c5eb77d7ac94c4a65f26af48Kenny Root } 1697735de3b38abbd6564082a819377673ee593744a6Kenny Root 1698af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final int callerUid = Binder.getCallingUid(); 1699af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbState obbState = new ObbState(filename, callerUid, token, nonce); 1700af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbAction action = new MountObbAction(obbState, key); 1701a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 1702a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1703a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1704a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Send to OBB handler: " + action.toString()); 170502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 170602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1707af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root public void unmountObb(String filename, boolean force, IObbActionListener token, int nonce) 1708af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throws RemoteException { 1709f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root if (filename == null) { 1710f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root throw new IllegalArgumentException("filename cannot be null"); 1711f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root } 1712f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root 1713af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final int callerUid = Binder.getCallingUid(); 1714af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbState obbState = new ObbState(filename, callerUid, token, nonce); 1715af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbAction action = new UnmountObbAction(obbState, force); 1716a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 1717a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1718a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1719a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Send to OBB handler: " + action.toString()); 1720a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 172102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 17225af0b916f850486cff4797355bf9e7dc3352fe00Jason parks public int decryptStorage(String password) { 1723f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (TextUtils.isEmpty(password)) { 1724f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks throw new IllegalArgumentException("password cannot be empty"); 17255af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 17265af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 17278888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 17288888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks "no permission to access the crypt keeper"); 17295af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 17305af0b916f850486cff4797355bf9e7dc3352fe00Jason parks waitForReady(); 17315af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 17325af0b916f850486cff4797355bf9e7dc3352fe00Jason parks if (DEBUG_EVENTS) { 17335af0b916f850486cff4797355bf9e7dc3352fe00Jason parks Slog.i(TAG, "decrypting storage..."); 17345af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 17355af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 17365af0b916f850486cff4797355bf9e7dc3352fe00Jason parks try { 17379ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks ArrayList<String> rsp = mConnector.doCommand("cryptfs checkpw " + password); 1738f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks String[] tokens = rsp.get(0).split(" "); 17399ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 1740f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (tokens == null || tokens.length != 2) { 17419ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks return -1; 17429ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks } 17439ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 1744f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks int code = Integer.parseInt(tokens[1]); 17459ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 17469ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks if (code == 0) { 17479ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks // Decrypt was successful. Post a delayed message before restarting in order 17489ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks // to let the UI to clear itself 17499ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks mHandler.postDelayed(new Runnable() { 17509ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks public void run() { 17519ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks mConnector.doCommand(String.format("cryptfs restart")); 17529ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks } 1753f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks }, 1000); // 1 second 17549ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks } 17559ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 17569ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks return code; 17575af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } catch (NativeDaemonConnectorException e) { 17585af0b916f850486cff4797355bf9e7dc3352fe00Jason parks // Decryption failed 17595af0b916f850486cff4797355bf9e7dc3352fe00Jason parks return e.getCode(); 17605af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 17615af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 17625af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 176356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks public int encryptStorage(String password) { 1764f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (TextUtils.isEmpty(password)) { 1765f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks throw new IllegalArgumentException("password cannot be empty"); 176656aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 176756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 17688888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 17698888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks "no permission to access the crypt keeper"); 177056aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 177156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks waitForReady(); 177256aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 177356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks if (DEBUG_EVENTS) { 17748888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks Slog.i(TAG, "encrypting storage..."); 177556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 177656aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 177756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks try { 17789ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks mConnector.doCommand(String.format("cryptfs enablecrypto inplace %s", password)); 177956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } catch (NativeDaemonConnectorException e) { 178056aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks // Encryption failed 178156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks return e.getCode(); 178256aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 178356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 178456aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks return 0; 178556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 178656aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 1787f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks public int changeEncryptionPassword(String password) { 1788f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (TextUtils.isEmpty(password)) { 1789f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks throw new IllegalArgumentException("password cannot be empty"); 1790f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 1791f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1792f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 1793f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks "no permission to access the crypt keeper"); 1794f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1795f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks waitForReady(); 1796f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1797f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (DEBUG_EVENTS) { 1798f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks Slog.i(TAG, "changing encryption password..."); 1799f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 1800f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1801f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks try { 1802f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks ArrayList<String> response = mConnector.doCommand("cryptfs changepw " + password); 1803f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1804f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks String[] tokens = response.get(0).split(" "); 1805f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1806f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (tokens == null || tokens.length != 2) { 1807f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks return -1; 1808f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 1809f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1810f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks return Integer.parseInt(tokens[1]); 1811f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } catch (NativeDaemonConnectorException e) { 1812f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks // Encryption failed 1813f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks return e.getCode(); 1814f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 1815f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 1816f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 18172f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood public Parcelable[] getVolumeList() { 18182f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood synchronized(mVolumes) { 18192f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood int size = mVolumes.size(); 18202f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood Parcelable[] result = new Parcelable[size]; 18212f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood for (int i = 0; i < size; i++) { 18222f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood result[i] = mVolumes.get(i); 18238fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood } 18248fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood return result; 18258fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood } 18268fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood } 18278fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood 1828af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private void addObbStateLocked(ObbState obbState) throws RemoteException { 1829af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IBinder binder = obbState.getBinder(); 1830af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root List<ObbState> obbStates = mObbMounts.get(binder); 18315919ac6b4188285324646772501ef4b97b353cf4Kenny Root 1832af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates == null) { 1833af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates = new ArrayList<ObbState>(); 1834af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.put(binder, obbStates); 1835af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 1836af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root for (final ObbState o : obbStates) { 1837af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (o.filename.equals(obbState.filename)) { 1838af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalStateException("Attempt to add ObbState twice. " 1839af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + "This indicates an error in the MountService logic."); 18405919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 18415919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 184202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 184302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1844af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates.add(obbState); 1845af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 1846af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState.link(); 1847af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (RemoteException e) { 1848af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root /* 1849af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * The binder died before we could link it, so clean up our state 1850af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * and return failure. 1851af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root */ 1852af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates.remove(obbState); 1853af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.isEmpty()) { 1854af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.remove(binder); 185505105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 18565919ac6b4188285324646772501ef4b97b353cf4Kenny Root 1857af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Rethrow the error so mountObb can get it 1858af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw e; 185902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 1860af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1861af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbPathToStateMap.put(obbState.filename, obbState); 1862a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 186302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1864af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private void removeObbStateLocked(ObbState obbState) { 1865af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IBinder binder = obbState.getBinder(); 1866af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStates = mObbMounts.get(binder); 1867af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates != null) { 1868af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.remove(obbState)) { 1869af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState.unlink(); 1870af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1871af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.isEmpty()) { 1872af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.remove(binder); 1873af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 187438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 1875af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1876af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbPathToStateMap.remove(obbState.filename); 187738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 187838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 1879a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private class ObbActionHandler extends Handler { 1880a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean mBound = false; 1881480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root private final List<ObbAction> mActions = new LinkedList<ObbAction>(); 1882a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1883a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbActionHandler(Looper l) { 1884a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(l); 1885a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1886a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1887a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 1888a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleMessage(Message msg) { 1889a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root switch (msg.what) { 1890a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_RUN_ACTION: { 1891480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root final ObbAction action = (ObbAction) msg.obj; 1892a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1893a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1894a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString()); 1895a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1896a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // If a bind was already initiated we don't really 1897a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // need to do anything. The pending install 1898a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // will be processed later on. 1899a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!mBound) { 1900a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // If this is the only one pending we might 1901a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // have to bind to the service again. 1902a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!connectToService()) { 1903a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Failed to bind to media container service"); 1904a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 1905a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return; 1906a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1907a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1908735de3b38abbd6564082a819377673ee593744a6Kenny Root 1909735de3b38abbd6564082a819377673ee593744a6Kenny Root mActions.add(action); 1910a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 1911a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1912a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_BOUND: { 1913a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1914a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_BOUND"); 1915a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (msg.obj != null) { 1916a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContainerService = (IMediaContainerService) msg.obj; 1917a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1918a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mContainerService == null) { 1919a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Something seriously wrong. Bail out 1920a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Cannot bind to media container service"); 1921a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root for (ObbAction action : mActions) { 1922a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Indicate service bind error 1923a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 1924a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1925a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.clear(); 1926a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else if (mActions.size() > 0) { 1927480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root final ObbAction action = mActions.get(0); 1928a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (action != null) { 1929a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.execute(this); 1930a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1931a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 1932a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Should never happen ideally. 1933a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.w(TAG, "Empty queue"); 1934a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1935a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 1936a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1937a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_RECONNECT: { 1938a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1939a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_RECONNECT"); 1940a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() > 0) { 1941a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mBound) { 1942a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root disconnectService(); 1943a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1944a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!connectToService()) { 1945a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Failed to bind to media container service"); 1946a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root for (ObbAction action : mActions) { 1947a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Indicate service bind error 1948a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 1949a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1950a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.clear(); 1951a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1952a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1953a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 1954a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1955a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_UNBIND: { 1956a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1957a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_UNBIND"); 1958a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1959a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Delete pending install 1960a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() > 0) { 1961a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.remove(0); 1962a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1963a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() == 0) { 1964a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mBound) { 1965a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root disconnectService(); 1966a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1967a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 1968a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // There are more pending requests in queue. 1969a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Just post MCS_BOUND message to trigger processing 1970a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // of next pending install. 1971a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND); 1972a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1973a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 1974a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1975af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root case OBB_FLUSH_MOUNT_STATE: { 1976af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final String path = (String) msg.obj; 1977af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1978af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 1979af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.i(TAG, "Flushing all OBB state for path " + path); 1980af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1981af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 1982af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>(); 1983af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1984af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Iterator<Entry<String, ObbState>> i = 1985af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbPathToStateMap.entrySet().iterator(); 1986af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (i.hasNext()) { 1987af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Entry<String, ObbState> obbEntry = i.next(); 1988af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1989af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root /* 1990af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * If this entry's source file is in the volume path 1991af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * that got unmounted, remove it because it's no 1992af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * longer valid. 1993af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root */ 1994af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbEntry.getKey().startsWith(path)) { 1995af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStatesToRemove.add(obbEntry.getValue()); 1996af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1997af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1998af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1999af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root for (final ObbState obbState : obbStatesToRemove) { 2000af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 2001af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.i(TAG, "Removing state for " + obbState.filename); 2002af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2003af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root removeObbStateLocked(obbState); 2004af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2005af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 2006af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState.token.onObbResult(obbState.filename, obbState.nonce, 2007af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root OnObbStateChangeListener.UNMOUNTED); 2008af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (RemoteException e) { 2009af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.i(TAG, "Couldn't send unmount notification for OBB: " 2010af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + obbState.filename); 2011af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2012af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2013af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2014af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root break; 2015af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 201602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 201702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 201802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2019a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean connectToService() { 2020a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2021a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Trying to bind to DefaultContainerService"); 2022a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2023a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); 2024a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) { 2025a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mBound = true; 2026a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return true; 202702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 2028a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return false; 2029a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2030a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2031a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private void disconnectService() { 2032a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContainerService = null; 2033a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mBound = false; 2034a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContext.unbindService(mDefContainerConn); 203502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 203602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 203702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2038a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root abstract class ObbAction { 2039a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int MAX_RETRIES = 3; 2040a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private int mRetries; 204102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2042a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbState mObbState; 2043a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2044a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbAction(ObbState obbState) { 2045a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbState = obbState; 204602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 204702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2048a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void execute(ObbActionHandler handler) { 2049a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root try { 2050a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2051a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Starting to execute action: " + this.toString()); 2052a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mRetries++; 2053a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mRetries > MAX_RETRIES) { 2054a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); 2055480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 2056a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleError(); 2057a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return; 2058a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 2059a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleExecute(); 2060a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2061a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Posting install MCS_UNBIND"); 2062a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 2063a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2064a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } catch (RemoteException e) { 2065a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2066a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Posting install MCS_RECONNECT"); 2067a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT); 2068a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } catch (Exception e) { 2069a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2070a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.d(TAG, "Error handling OBB action", e); 2071a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleError(); 207217eb6fb07cc6965f09c51adc70b3c291f57a784aKenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 207302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 2074a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 207502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 207605105f7abe02b2dff91d6260b3628c8b97816babKenny Root abstract void handleExecute() throws RemoteException, IOException; 2077a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root abstract void handleError(); 207838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 207938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root protected ObbInfo getObbInfo() throws IOException { 208038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root ObbInfo obbInfo; 208138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root try { 208238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root obbInfo = mContainerService.getObbInfo(mObbState.filename); 208338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } catch (RemoteException e) { 208438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for " 208538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root + mObbState.filename); 208638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root obbInfo = null; 208738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 208838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root if (obbInfo == null) { 208938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root throw new IOException("Couldn't read OBB file: " + mObbState.filename); 209038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 209138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return obbInfo; 209238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 209338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2094af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root protected void sendNewStatusOrIgnore(int status) { 2095af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (mObbState == null || mObbState.token == null) { 2096af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2097af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2098af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 209938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root try { 2100af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbState.token.onObbResult(mObbState.filename, mObbState.nonce, status); 210138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } catch (RemoteException e) { 210238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged"); 210338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 210438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2105a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2106a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2107a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class MountObbAction extends ObbAction { 2108a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private String mKey; 2109a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2110a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root MountObbAction(ObbState obbState, String key) { 2111a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(obbState); 2112a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mKey = key; 2113a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2114a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 21155af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 2116735de3b38abbd6564082a819377673ee593744a6Kenny Root public void handleExecute() throws IOException, RemoteException { 2117af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root waitForReady(); 2118af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root warnOnNotMounted(); 2119af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 212038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root final ObbInfo obbInfo = getObbInfo(); 212138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2122af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mObbState.callerUid)) { 2123af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename 2124af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + " which is owned by " + obbInfo.packageName); 2125af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); 2126af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2127af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2128af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2129af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final boolean isMounted; 2130af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 2131af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root isMounted = mObbPathToStateMap.containsKey(obbInfo.filename); 2132af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2133af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (isMounted) { 2134af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename); 2135af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED); 2136af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2137af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2138af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 213938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root /* 2140af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * The filename passed in might not be the canonical name, so just 2141af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * set the filename to the canonicalized version. 214238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root */ 2143af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbState.filename = obbInfo.filename; 214438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2145af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final String hashedKey; 2146af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (mKey == null) { 2147af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root hashedKey = "none"; 2148af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 2149af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 21503b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 21513b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 21523b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt, 21533b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE); 21543b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root SecretKey key = factory.generateSecret(ks); 21553b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root BigInteger bi = new BigInteger(key.getEncoded()); 21563b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root hashedKey = bi.toString(16); 2157af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NoSuchAlgorithmException e) { 21583b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root Slog.e(TAG, "Could not load PBKDF2 algorithm", e); 21593b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 21603b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root return; 21613b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root } catch (InvalidKeySpecException e) { 21623b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e); 21633b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 2164af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 216538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2166a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2167a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2168af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int rc = StorageResultCode.OperationSucceeded; 2169af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root String cmd = String.format("obb mount %s %s %d", mObbState.filename, hashedKey, 2170af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbState.callerUid); 2171af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 2172af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mConnector.doCommand(cmd); 2173af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NativeDaemonConnectorException e) { 2174af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int code = e.getCode(); 2175af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (code != VoldResponseCode.OpFailedStorageBusy) { 2176af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedInternalError; 2177a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2178af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2179a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2180af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (rc == StorageResultCode.OperationSucceeded) { 2181af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 2182af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.d(TAG, "Successfully mounted OBB " + mObbState.filename); 218338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2184af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 2185af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root addObbStateLocked(mObbState); 2186a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 218738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2188af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED); 218902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } else { 219005105f7abe02b2dff91d6260b3628c8b97816babKenny Root Slog.e(TAG, "Couldn't mount OBB file: " + rc); 2191a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2192af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT); 219302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 219402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 219502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 21965af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 2197a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleError() { 2198af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 219902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 2200a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2201a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 2202a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public String toString() { 2203a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root StringBuilder sb = new StringBuilder(); 2204a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("MountObbAction{"); 2205a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("filename="); 2206a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.filename); 2207a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",callerUid="); 2208a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.callerUid); 2209a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",token="); 2210a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.token != null ? mObbState.token.toString() : "NULL"); 2211af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sb.append(",binder="); 2212af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sb.append(mObbState.token != null ? mObbState.getBinder().toString() : "null"); 2213a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append('}'); 2214a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return sb.toString(); 2215a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2216a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2217a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2218a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class UnmountObbAction extends ObbAction { 2219a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean mForceUnmount; 2220a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2221a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root UnmountObbAction(ObbState obbState, boolean force) { 2222a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(obbState); 2223a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mForceUnmount = force; 2224a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2225a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 22265af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 222738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root public void handleExecute() throws IOException { 2228af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root waitForReady(); 2229af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root warnOnNotMounted(); 2230af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 223138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root final ObbInfo obbInfo = getObbInfo(); 2232a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2233af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbState obbState; 223438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root synchronized (mObbMounts) { 2235af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState = mObbPathToStateMap.get(obbInfo.filename); 2236af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 223738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2238af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbState == null) { 2239af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED); 2240af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2241a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2242a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2243af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbState.callerUid != mObbState.callerUid) { 2244af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Permission denied attempting to unmount OBB " + obbInfo.filename 2245af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + " (owned by " + obbInfo.packageName + ")"); 2246af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); 2247af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2248af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2249a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2250af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbState.filename = obbInfo.filename; 225138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2252af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int rc = StorageResultCode.OperationSucceeded; 2253af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root String cmd = String.format("obb unmount %s%s", mObbState.filename, 2254af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root (mForceUnmount ? " force" : "")); 2255af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 2256af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mConnector.doCommand(cmd); 2257af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NativeDaemonConnectorException e) { 2258af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int code = e.getCode(); 2259af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (code == VoldResponseCode.OpFailedStorageBusy) { 2260af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedStorageBusy; 2261af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else if (code == VoldResponseCode.OpFailedStorageNotFound) { 2262af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // If it's not mounted then we've already won. 2263af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationSucceeded; 2264af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 2265af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedInternalError; 2266a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2267a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 226838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2269af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (rc == StorageResultCode.OperationSucceeded) { 2270af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 2271af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root removeObbStateLocked(obbState); 2272af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 227338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2274af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED); 227538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } else { 2276af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Could not mount OBB: " + mObbState.filename); 2277af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT); 227838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2279a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2280a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 22815af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 2282a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleError() { 2283af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 2284a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2285a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2286a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 2287a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public String toString() { 2288a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root StringBuilder sb = new StringBuilder(); 2289a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("UnmountObbAction{"); 2290a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("filename="); 2291a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.filename != null ? mObbState.filename : "null"); 2292a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",force="); 2293a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mForceUnmount); 2294a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",callerUid="); 2295a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.callerUid); 2296a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",token="); 2297a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.token != null ? mObbState.token.toString() : "null"); 2298735de3b38abbd6564082a819377673ee593744a6Kenny Root sb.append(",binder="); 2299af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sb.append(mObbState.token != null ? mObbState.getBinder().toString() : "null"); 2300a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append('}'); 2301a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return sb.toString(); 2302a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 230302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 230438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 230538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root @Override 230638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 230738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { 230838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root pw.println("Permission Denial: can't dump ActivityManager from from pid=" 230938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() 231038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root + " without permission " + android.Manifest.permission.DUMP); 231138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return; 231238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 231338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 231438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root synchronized (mObbMounts) { 2315af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(" mObbMounts:"); 231638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2317af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet().iterator(); 2318af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (binders.hasNext()) { 2319af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Entry<IBinder, List<ObbState>> e = binders.next(); 2320af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" Key="); pw.println(e.getKey().toString()); 2321af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStates = e.getValue(); 232238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root for (final ObbState obbState : obbStates) { 2323af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" "); pw.println(obbState.toString()); 232438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 232538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2326af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2327af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(""); 2328af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(" mObbPathToStateMap:"); 2329af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator(); 2330af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (maps.hasNext()) { 2331af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Entry<String, ObbState> e = maps.next(); 2332af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" "); pw.print(e.getKey()); 2333af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" -> "); pw.println(e.getValue().toString()); 2334af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 233538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 233638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 23379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 23389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2339