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