MountService.java revision 5ac72a29593ab9a20337a2225df52bdf4754be02
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.server; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport com.android.internal.app.IMediaContainerService; 202f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport com.android.internal.util.XmlUtils; 21c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport com.android.server.am.ActivityManagerService; 22cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Rootimport com.android.server.pm.PackageManagerService; 23dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkeyimport com.android.server.NativeDaemonConnector.Command; 24c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 258888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parksimport android.Manifest; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver; 27a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ComponentName; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter; 31a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ServiceConnection; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager; 3302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.content.res.ObbInfo; 342f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.Resources; 352f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.TypedArray; 362f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.XmlResourceParser; 37ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwoodimport android.hardware.usb.UsbManager; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri; 3902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.os.Binder; 40a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.Environment; 41c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Handler; 425f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.HandlerThread; 43a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.IBinder; 445f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.Looper; 45c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Message; 462f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.os.Parcelable; 474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehatimport android.os.RemoteException; 48fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapuimport android.os.ServiceManager; 49207e538350665cea00e1aa70b8094beca4a34e45San Mehatimport android.os.SystemClock; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties; 51f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport android.os.UserHandle; 52a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountService; 53a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountServiceListener; 54a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountShutdownObserver; 55a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IObbActionListener; 56af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Rootimport android.os.storage.OnObbStateChangeListener; 57a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.StorageResultCode; 582f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.os.storage.StorageVolume; 59f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parksimport android.text.TextUtils; 602f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.util.AttributeSet; 61a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehatimport android.util.Slog; 622f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.util.Xml; 632f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 642f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport org.xmlpull.v1.XmlPullParser; 652f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport org.xmlpull.v1.XmlPullParserException; 66a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 6738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.FileDescriptor; 6805105f7abe02b2dff91d6260b3628c8b97816babKenny Rootimport java.io.IOException; 6938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.PrintWriter; 703b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.math.BigInteger; 71735de3b38abbd6564082a819377673ee593744a6Kenny Rootimport java.security.NoSuchAlgorithmException; 723b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.InvalidKeySpecException; 733b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.KeySpec; 7422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehatimport java.util.ArrayList; 75a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.HashMap; 766cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehatimport java.util.HashSet; 7738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Iterator; 78a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.LinkedList; 79a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.List; 80a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.Map; 8138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Map.Entry; 8251a573c76737733638c475f52e441c814e6645ccKenny Rootimport java.util.concurrent.CountDownLatch; 8351a573c76737733638c475f52e441c814e6645ccKenny Rootimport java.util.concurrent.TimeUnit; 848fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwoodimport java.util.Set; 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 863b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKey; 873b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKeyFactory; 883b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.spec.PBEKeySpec; 893b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 91b104340496e3a531e26c8f428c808eca0e039f50San Mehat * MountService implements back-end services for platform storage 92b104340496e3a531e26c8f428c808eca0e039f50San Mehat * management. 93b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @hide - Applications should use android.os.storage.StorageManager 94b104340496e3a531e26c8f428c808eca0e039f50San Mehat * to access the MountService. 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 96fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkeyclass MountService extends IMountService.Stub 97fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey implements INativeDaemonConnectorCallbacks, Watchdog.Monitor { 985af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 99b104340496e3a531e26c8f428c808eca0e039f50San Mehat private static final boolean LOCAL_LOGD = false; 1008a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu private static final boolean DEBUG_UNMOUNT = false; 1018a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu private static final boolean DEBUG_EVENTS = false; 102b7db2726e91f1d9480359d0f83b9cb7769906b34Kenny Root private static final boolean DEBUG_OBB = false; 10302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 10407714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root // Disable this since it messes up long-running cryptfs operations. 10507714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root private static final boolean WATCHDOG_ENABLE = false; 10607714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String TAG = "MountService"; 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 109305bcbf0c961840c4505770d084a1caacc074dbbKenny Root private static final String VOLD_TAG = "VoldConnector"; 110305bcbf0c961840c4505770d084a1caacc074dbbKenny Root 111cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root /** Maximum number of ASEC containers allowed to be mounted. */ 112cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root private static final int MAX_CONTAINERS = 250; 113cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root 1144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Internal vold volume state constants 1164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 1177fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat class VolumeState { 1187fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Init = -1; 1197fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int NoMedia = 0; 1207fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Idle = 1; 1217fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Pending = 2; 1227fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Checking = 3; 1237fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Mounted = 4; 1247fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Unmounting = 5; 1257fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Formatting = 6; 1267fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Shared = 7; 1277fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int SharedMnt = 8; 1287fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 1297fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 1304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Internal vold response code constants 1324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 13322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat class VoldResponseCode { 1344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 100 series - Requestion action was initiated; expect another reply 1364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * before proceeding with a new command. 1374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 13822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeListResult = 110; 13922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int AsecListResult = 111; 140c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat public static final int StorageUsersListResult = 112; 14122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 200 series - Requestion action has been successfully completed. 1444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 1454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int ShareStatusResult = 210; 14622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int AsecPathResult = 211; 1474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int ShareEnabledResult = 212; 14822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 400 series - Command was accepted, but the requested action 1514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * did not take place. 1524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 1534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedNoMedia = 401; 1544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedMediaBlank = 402; 1554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedMediaCorrupt = 403; 1564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedVolNotMounted = 404; 157d970998b0d489774ad1c5b94b47d233912f00214San Mehat public static final int OpFailedStorageBusy = 405; 1582d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat public static final int OpFailedStorageNotFound = 406; 1594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 600 series - Unsolicited broadcasts. 1624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 16322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeStateChange = 605; 16422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeDiskInserted = 630; 16522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeDiskRemoved = 631; 16622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeBadRemoval = 632; 16722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 16822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private Context mContext; 1704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private NativeDaemonConnector mConnector; 1712f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood private final ArrayList<StorageVolume> mVolumes = new ArrayList<StorageVolume>(); 1722f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood private StorageVolume mPrimaryVolume; 1737fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood private final HashMap<String, String> mVolumeStates = new HashMap<String, String>(); 174a5250c93928e256738125b265e10c96c3575597eMike Lockwood private final HashMap<String, StorageVolume> mVolumeMap = new HashMap<String, StorageVolume>(); 1757fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood private String mExternalStoragePath; 1764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private PackageManagerService mPms; 1774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private boolean mUmsEnabling; 178ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood private boolean mUmsAvailable = false; 1790eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Used as a lock for methods that register/unregister listeners. 1800eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu final private ArrayList<MountServiceBinderListener> mListeners = 1810eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu new ArrayList<MountServiceBinderListener>(); 1826a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private boolean mBooted = false; 18351a573c76737733638c475f52e441c814e6645ccKenny Root private CountDownLatch mConnectedSignal = new CountDownLatch(1); 18451a573c76737733638c475f52e441c814e6645ccKenny Root private CountDownLatch mAsecsScanned = new CountDownLatch(1); 1856a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private boolean mSendUmsConnectedOnBoot = false; 18603559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood // true if we should fake MEDIA_MOUNTED state for external storage 18703559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood private boolean mEmulateExternalStorage = false; 188fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapu 1896cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat /** 1906cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat * Private hash of currently mounted secure containers. 1910eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * Used as a lock in methods to manipulate secure containers. 1926cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat */ 1930eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu final private HashSet<String> mAsecMountSet = new HashSet<String>(); 1946cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 19502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root /** 1963b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * The size of the crypto algorithm key in bits for OBB files. Currently 1973b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * Twofish is used which takes 128-bit keys. 1983b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root */ 1993b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128; 2003b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 2013b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root /** 2023b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * The number of times to run SHA1 in the PBKDF2 function for OBB files. 2033b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * 1024 is reasonably secure and not too slow. 2043b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root */ 2053b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root private static final int PBKDF2_HASH_ROUNDS = 1024; 2063b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 2073b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root /** 208a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * Mounted OBB tracking information. Used to track the current state of all 209a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * OBBs. 210a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root */ 211735de3b38abbd6564082a819377673ee593744a6Kenny Root final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>(); 212a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>(); 213a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 214a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class ObbState implements IBinder.DeathRecipient { 215af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root public ObbState(String filename, int callerUid, IObbActionListener token, int nonce) 216735de3b38abbd6564082a819377673ee593744a6Kenny Root throws RemoteException { 217a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root this.filename = filename; 218a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root this.callerUid = callerUid; 219af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root this.token = token; 220af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root this.nonce = nonce; 221a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 222a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 223a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // OBB source filename 224af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root String filename; 225a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 226a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Binder.callingUid() 22705105f7abe02b2dff91d6260b3628c8b97816babKenny Root final public int callerUid; 228a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 229af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Token of remote Binder caller 230af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IObbActionListener token; 231af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 232af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Identifier to pass back to the token 233af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final int nonce; 234a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 235735de3b38abbd6564082a819377673ee593744a6Kenny Root public IBinder getBinder() { 236735de3b38abbd6564082a819377673ee593744a6Kenny Root return token.asBinder(); 237735de3b38abbd6564082a819377673ee593744a6Kenny Root } 238735de3b38abbd6564082a819377673ee593744a6Kenny Root 239a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 240a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void binderDied() { 241a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbAction action = new UnmountObbAction(this, true); 242a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 243735de3b38abbd6564082a819377673ee593744a6Kenny Root } 244a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2455919ac6b4188285324646772501ef4b97b353cf4Kenny Root public void link() throws RemoteException { 2465919ac6b4188285324646772501ef4b97b353cf4Kenny Root getBinder().linkToDeath(this, 0); 2475919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 2485919ac6b4188285324646772501ef4b97b353cf4Kenny Root 2495919ac6b4188285324646772501ef4b97b353cf4Kenny Root public void unlink() { 250735de3b38abbd6564082a819377673ee593744a6Kenny Root getBinder().unlinkToDeath(this, 0); 251a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 25238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 25338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root @Override 25438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root public String toString() { 25538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root StringBuilder sb = new StringBuilder("ObbState{"); 25638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append("filename="); 25738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(filename); 25838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(",token="); 25938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(token.toString()); 26038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(",callerUid="); 26138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(callerUid); 26238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append('}'); 26338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return sb.toString(); 26438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 265a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 266a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 267a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // OBB Action Handler 268a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private ObbActionHandler mObbActionHandler; 269a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 270a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // OBB action handler messages 271a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_RUN_ACTION = 1; 272a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_BOUND = 2; 273a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_UNBIND = 3; 274a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_RECONNECT = 4; 275af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private static final int OBB_FLUSH_MOUNT_STATE = 5; 276a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 277a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root /* 278a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * Default Container Service information 27902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root */ 280a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName( 281a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService"); 282a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 283a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection(); 284a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 285a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class DefaultContainerConnection implements ServiceConnection { 286a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void onServiceConnected(ComponentName name, IBinder service) { 287a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 288a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "onServiceConnected"); 289a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service); 290a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs)); 291a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 292a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 293a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void onServiceDisconnected(ComponentName name) { 294a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 295a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "onServiceDisconnected"); 296a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 297a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root }; 298a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 299a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Used in the ObbActionHandler 300a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private IMediaContainerService mContainerService = null; 30102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 30202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root // Handler messages 303c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_PM_UPDATE = 1; 304c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_PM_DONE = 2; 305c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_MS = 3; 306c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int RETRY_UNMOUNT_DELAY = 30; // in ms 307c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int MAX_UNMOUNT_RETRIES = 4; 308c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 309c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu class UnmountCallBack { 31005105f7abe02b2dff91d6260b3628c8b97816babKenny Root final String path; 31105105f7abe02b2dff91d6260b3628c8b97816babKenny Root final boolean force; 31213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo final boolean removeEncryption; 313c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu int retries; 314c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 31513c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo UnmountCallBack(String path, boolean force, boolean removeEncryption) { 316c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu retries = 0; 317c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu this.path = path; 318c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu this.force = force; 31913c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo this.removeEncryption = removeEncryption; 320c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 3210eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3220eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu void handleFinished() { 323a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path); 32413c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo doUnmountVolume(path, true, removeEncryption); 3250eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 3260eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 3270eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3280eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu class UmsEnableCallBack extends UnmountCallBack { 32905105f7abe02b2dff91d6260b3628c8b97816babKenny Root final String method; 3300eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3310eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu UmsEnableCallBack(String path, String method, boolean force) { 33213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo super(path, force, false); 3330eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu this.method = method; 3340eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 3350eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3360eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu @Override 3370eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu void handleFinished() { 3380eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu super.handleFinished(); 3390eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doShareUnshareVolume(path, method, true); 3400eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 341c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 342c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 3436ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu class ShutdownCallBack extends UnmountCallBack { 3446ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu IMountShutdownObserver observer; 3456ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu ShutdownCallBack(String path, IMountShutdownObserver observer) { 34613c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo super(path, true, false); 3476ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu this.observer = observer; 3486ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3496ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3506ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu @Override 3516ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu void handleFinished() { 35213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo int ret = doUnmountVolume(path, true, removeEncryption); 3536ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (observer != null) { 3546ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu try { 3556ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu observer.onShutDownComplete(ret); 3566ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } catch (RemoteException e) { 357a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "RemoteException when shutting down"); 3586ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3596ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3606ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3616ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3626ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3635f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler class MountServiceHandler extends Handler { 364c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>(); 365e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu boolean mUpdatingStatus = false; 3666ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3675f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler MountServiceHandler(Looper l) { 3685f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler super(l); 3695f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler } 3705f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler 3715af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 372c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu public void handleMessage(Message msg) { 373c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu switch (msg.what) { 374c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_PM_UPDATE: { 375a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_UPDATE"); 376c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = (UnmountCallBack) msg.obj; 377c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu mForceUnmounts.add(ucb); 378a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, " registered = " + mUpdatingStatus); 3796ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Register only if needed. 380e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu if (!mUpdatingStatus) { 381a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Updating external media status on PackageManager"); 382e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mUpdatingStatus = true; 383e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(false, true); 384c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 385c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 386c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 387c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_PM_DONE: { 388a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_DONE"); 389a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Updated status. Processing requests"); 390e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mUpdatingStatus = false; 3916ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int size = mForceUnmounts.size(); 3926ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int sizeArr[] = new int[size]; 3936ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int sizeArrN = 0; 3947af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Kill processes holding references first 3957af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ActivityManagerService ams = (ActivityManagerService) 3967af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ServiceManager.getService("activity"); 3976ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu for (int i = 0; i < size; i++) { 3986ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu UnmountCallBack ucb = mForceUnmounts.get(i); 3996ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu String path = ucb.path; 4006ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu boolean done = false; 4016ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (!ucb.force) { 402c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu done = true; 403c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } else { 4046ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int pids[] = getStorageUsers(path); 4056ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (pids == null || pids.length == 0) { 4066ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu done = true; 4076ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } else { 4086ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Eliminate system process here? 409648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn ams.killPids(pids, "unmount media", true); 4107af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Confirm if file references have been freed. 4117af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu pids = getStorageUsers(path); 4127af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu if (pids == null || pids.length == 0) { 4137af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu done = true; 414c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 415c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 416c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 4177af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) { 4187af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Retry again 4197af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu Slog.i(TAG, "Retrying to kill storage users again"); 4207af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.sendMessageDelayed( 4217af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.obtainMessage(H_UNMOUNT_PM_DONE, 4227af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ucb.retries++), 4237af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu RETRY_UNMOUNT_DELAY); 424c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } else { 4256ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (ucb.retries >= MAX_UNMOUNT_RETRIES) { 4267af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu Slog.i(TAG, "Failed to unmount media inspite of " + 4277af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu MAX_UNMOUNT_RETRIES + " retries. Forcibly killing processes now"); 4286ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 4297af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu sizeArr[sizeArrN++] = i; 4307af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS, 4317af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ucb)); 432c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 433c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 4346ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Remove already processed elements from list. 4356ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu for (int i = (sizeArrN-1); i >= 0; i--) { 4366ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu mForceUnmounts.remove(sizeArr[i]); 4376ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 438c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 439c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 440c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_MS : { 441a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_MS"); 442c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = (UnmountCallBack) msg.obj; 4430eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu ucb.handleFinished(); 444c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 445c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 446c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 447c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 448c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu }; 4495f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler final private HandlerThread mHandlerThread; 4505f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler final private Handler mHandler; 451c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 45251a573c76737733638c475f52e441c814e6645ccKenny Root void waitForAsecScan() { 45351a573c76737733638c475f52e441c814e6645ccKenny Root waitForLatch(mAsecsScanned); 45451a573c76737733638c475f52e441c814e6645ccKenny Root } 45551a573c76737733638c475f52e441c814e6645ccKenny Root 456207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void waitForReady() { 45751a573c76737733638c475f52e441c814e6645ccKenny Root waitForLatch(mConnectedSignal); 45851a573c76737733638c475f52e441c814e6645ccKenny Root } 45951a573c76737733638c475f52e441c814e6645ccKenny Root 46051a573c76737733638c475f52e441c814e6645ccKenny Root private void waitForLatch(CountDownLatch latch) { 46151a573c76737733638c475f52e441c814e6645ccKenny Root if (latch == null) { 46251a573c76737733638c475f52e441c814e6645ccKenny Root return; 46351a573c76737733638c475f52e441c814e6645ccKenny Root } 46451a573c76737733638c475f52e441c814e6645ccKenny Root 46551a573c76737733638c475f52e441c814e6645ccKenny Root for (;;) { 46651a573c76737733638c475f52e441c814e6645ccKenny Root try { 46751a573c76737733638c475f52e441c814e6645ccKenny Root if (latch.await(5000, TimeUnit.MILLISECONDS)) { 468207e538350665cea00e1aa70b8094beca4a34e45San Mehat return; 46951a573c76737733638c475f52e441c814e6645ccKenny Root } else { 47051a573c76737733638c475f52e441c814e6645ccKenny Root Slog.w(TAG, "Thread " + Thread.currentThread().getName() 47151a573c76737733638c475f52e441c814e6645ccKenny Root + " still waiting for MountService ready..."); 472207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 47351a573c76737733638c475f52e441c814e6645ccKenny Root } catch (InterruptedException e) { 47451a573c76737733638c475f52e441c814e6645ccKenny Root Slog.w(TAG, "Interrupt while waiting for MountService to be ready."); 475207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 476207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 4771f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 47802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 479444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 4805af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onReceive(Context context, Intent intent) { 48291c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat String action = intent.getAction(); 48391c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 48491c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { 485207e538350665cea00e1aa70b8094beca4a34e45San Mehat mBooted = true; 48622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 487c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen /* 488c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * In the simulator, we need to broadcast a volume mounted event 489c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * to make the media scanner run. 490c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen */ 491c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen if ("simulator".equals(SystemProperties.get("ro.product.device"))) { 49284338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood notifyVolumeStateChange(null, "/sdcard", VolumeState.NoMedia, 49384338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood VolumeState.Mounted); 494c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen return; 495c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen } 496fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat new Thread() { 4975af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 498fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat public void run() { 499fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat try { 50084338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood // it is not safe to call vold with mVolumeStates locked 50184338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood // so we make a copy of the paths and states and process them 50284338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood // outside the lock 503fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey String[] paths; 504fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey String[] states; 50584338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood int count; 5067fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood synchronized (mVolumeStates) { 50784338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood Set<String> keys = mVolumeStates.keySet(); 50884338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood count = keys.size(); 509444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo paths = keys.toArray(new String[count]); 51084338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood states = new String[count]; 51184338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood for (int i = 0; i < count; i++) { 51284338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood states[i] = mVolumeStates.get(paths[i]); 51384338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood } 51484338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood } 51584338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood 51684338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood for (int i = 0; i < count; i++) { 51784338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood String path = paths[i]; 51884338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood String state = states[i]; 51984338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood 52084338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood if (state.equals(Environment.MEDIA_UNMOUNTED)) { 52184338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood int rc = doMountVolume(path); 52284338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood if (rc != StorageResultCode.OperationSucceeded) { 52384338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood Slog.e(TAG, String.format("Boot-time mount failed (%d)", 52484338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood rc)); 5257fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 52684338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood } else if (state.equals(Environment.MEDIA_SHARED)) { 52784338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood /* 52884338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood * Bootstrap UMS enabled state since vold indicates 52984338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood * the volume is shared (runtime restart while ums enabled) 53084338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood */ 53184338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood notifyVolumeStateChange(null, path, VolumeState.NoMedia, 53284338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood VolumeState.Shared); 533fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } 534fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } 5356a254403235196692b1769d2fe281b0852c0cc25San Mehat 53680e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood /* notify external storage has mounted to trigger media scanner */ 53780e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood if (mEmulateExternalStorage) { 53880e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood notifyVolumeStateChange(null, 53980e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood Environment.getExternalStorageDirectory().getPath(), 54080e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood VolumeState.NoMedia, VolumeState.Mounted); 54180e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood } 54280e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood 5436a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat /* 5446a254403235196692b1769d2fe281b0852c0cc25San Mehat * If UMS was connected on boot, send the connected event 5456a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat * now that we're up. 5466a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat */ 5476a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat if (mSendUmsConnectedOnBoot) { 5486a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat sendUmsIntent(true); 5496a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat mSendUmsConnectedOnBoot = false; 5506a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } 551fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } catch (Exception ex) { 552a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Boot-time mount exception", ex); 553fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } 554207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 555fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat }.start(); 556ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood } else if (action.equals(UsbManager.ACTION_USB_STATE)) { 557ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood boolean available = (intent.getBooleanExtra(UsbManager.USB_CONNECTED, false) && 558ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood intent.getBooleanExtra(UsbManager.USB_FUNCTION_MASS_STORAGE, false)); 559ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood notifyShareAvailabilityChange(available); 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 5634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private final class MountServiceBinderListener implements IBinder.DeathRecipient { 5644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final IMountServiceListener mListener; 56591c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 5664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener(IMountServiceListener listener) { 5674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListener = listener; 56802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 56991c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 57091c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 5714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void binderDied() { 572a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!"); 573a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root synchronized (mListeners) { 5744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(this); 5754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListener.asBinder().unlinkToDeath(this, 0); 57691c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 57791c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 57891c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 57991c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 5800eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private void doShareUnshareVolume(String path, String method, boolean enable) { 5814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat // TODO: Add support for multiple share methods 5824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!method.equals("ums")) { 5834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new IllegalArgumentException(String.format("Method %s not supported", method)); 5847fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 587dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("volume", enable ? "share" : "unshare", path, method); 5884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 589a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to share/unshare", e); 59022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 593207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void updatePublicVolumeState(String path, String state) { 5947fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String oldState; 5957fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood synchronized(mVolumeStates) { 5967fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood oldState = mVolumeStates.put(path, state); 5977fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 5987fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state.equals(oldState)) { 5997fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.w(TAG, String.format("Duplicate state transition (%s -> %s) for %s", 6007fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood state, state, path)); 601b104340496e3a531e26c8f428c808eca0e039f50San Mehat return; 602b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 603af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 6047fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.d(TAG, "volume state changed for " + path + " (" + oldState + " -> " + state + ")"); 6057fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 6067fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (path.equals(mExternalStoragePath)) { 6077fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood // Update state on PackageManager, but only of real events 6087fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (!mEmulateExternalStorage) { 6097fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (Environment.MEDIA_UNMOUNTED.equals(state)) { 6107fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood mPms.updateExternalMediaStatus(false, false); 6117fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 6127fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood /* 6137fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * Some OBBs might have been unmounted when this volume was 6147fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * unmounted, so send a message to the handler to let it know to 6157fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * remove those from the list of mounted OBBS. 6167fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood */ 6177fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage( 6187fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood OBB_FLUSH_MOUNT_STATE, path)); 6197fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } else if (Environment.MEDIA_MOUNTED.equals(state)) { 6207fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood mPms.updateExternalMediaStatus(true, false); 6217fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 62203559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood } 6238a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 6244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 6254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for (int i = mListeners.size() -1; i >= 0; i--) { 6264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = mListeners.get(i); 6274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 628b104340496e3a531e26c8f428c808eca0e039f50San Mehat bl.mListener.onStorageStateChanged(path, oldState, state); 6294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 630a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener dead"); 6314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(i); 6324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 633a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener failed", ex); 6344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 63922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat /** 64022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * 64122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * Callback from NativeDaemonConnector 64222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat */ 64322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public void onDaemonConnected() { 6445b77dab23469273d41f9c530d947ac055765e6eaSan Mehat /* 6455b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * Since we'll be calling back into the NativeDaemonConnector, 6465b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * we need to do our work in a new thread. 6475b77dab23469273d41f9c530d947ac055765e6eaSan Mehat */ 64851a573c76737733638c475f52e441c814e6645ccKenny Root new Thread("MountService#onDaemonConnected") { 6495af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 6507fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public void run() { 6515b77dab23469273d41f9c530d947ac055765e6eaSan Mehat /** 6525b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * Determine media state and UMS detection status 6535b77dab23469273d41f9c530d947ac055765e6eaSan Mehat */ 6547fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat try { 655dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final String[] vols = NativeDaemonEvent.filterMessageList( 656dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.executeForList("volume", "list"), 657dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey VoldResponseCode.VolumeListResult); 6585b77dab23469273d41f9c530d947ac055765e6eaSan Mehat for (String volstr : vols) { 6595b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String[] tok = volstr.split(" "); 6605b77dab23469273d41f9c530d947ac055765e6eaSan Mehat // FMT: <label> <mountpoint> <state> 6617fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String path = tok[1]; 6627fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String state = Environment.MEDIA_REMOVED; 6637fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 6645b77dab23469273d41f9c530d947ac055765e6eaSan Mehat int st = Integer.parseInt(tok[2]); 6655b77dab23469273d41f9c530d947ac055765e6eaSan Mehat if (st == VolumeState.NoMedia) { 6665b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_REMOVED; 6675b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Idle) { 668207e538350665cea00e1aa70b8094beca4a34e45San Mehat state = Environment.MEDIA_UNMOUNTED; 6695b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Mounted) { 6705b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_MOUNTED; 671a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Media already mounted on daemon connection"); 6725b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Shared) { 6735b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_SHARED; 674a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Media shared on daemon connection"); 6755b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else { 6765b77dab23469273d41f9c530d947ac055765e6eaSan Mehat throw new Exception(String.format("Unexpected state %d", st)); 6777fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6787fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 6797fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state != null) { 6807fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state); 6817fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood updatePublicVolumeState(path, state); 6827fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 683c2a39471642e31d7350910612e40d078b825173aSan Mehat } 6845b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } catch (Exception e) { 685a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Error processing initial volume state", e); 6867fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood updatePublicVolumeState(mExternalStoragePath, Environment.MEDIA_REMOVED); 6877fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6887fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 689207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 6909ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks * Now that we've done our initialization, release 691207e538350665cea00e1aa70b8094beca4a34e45San Mehat * the hounds! 692207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 69351a573c76737733638c475f52e441c814e6645ccKenny Root mConnectedSignal.countDown(); 69451a573c76737733638c475f52e441c814e6645ccKenny Root mConnectedSignal = null; 69551a573c76737733638c475f52e441c814e6645ccKenny Root 69651a573c76737733638c475f52e441c814e6645ccKenny Root // Let package manager load internal ASECs. 69751a573c76737733638c475f52e441c814e6645ccKenny Root mPms.scanAvailableAsecs(); 69851a573c76737733638c475f52e441c814e6645ccKenny Root 69951a573c76737733638c475f52e441c814e6645ccKenny Root // Notify people waiting for ASECs to be scanned that it's done. 70051a573c76737733638c475f52e441c814e6645ccKenny Root mAsecsScanned.countDown(); 70151a573c76737733638c475f52e441c814e6645ccKenny Root mAsecsScanned = null; 7027fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 7037fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat }.start(); 7047fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 7057fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 70622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat /** 70722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * Callback from NativeDaemonConnector 70822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat */ 70922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public boolean onEvent(int code, String raw, String[] cooked) { 7108a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (DEBUG_EVENTS) { 7118a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu StringBuilder builder = new StringBuilder(); 7128a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append("onEvent::"); 7138a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" raw= " + raw); 7148a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (cooked != null) { 7158a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" cooked = " ); 7168a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu for (String str : cooked) { 7178a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" " + str); 7188a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 7198a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 720a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, builder.toString()); 7218a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 72222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat if (code == VoldResponseCode.VolumeStateChange) { 7234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 7244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * One of the volumes we're managing has changed state. 7254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Format: "NNN Volume <label> <path> state changed 7264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * from <old_#> (<old_str>) to <new_#> (<new_str>)" 7274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 72822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat notifyVolumeStateChange( 72922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat cooked[2], cooked[3], Integer.parseInt(cooked[7]), 73022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat Integer.parseInt(cooked[10])); 7314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if ((code == VoldResponseCode.VolumeDiskInserted) || 7324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat (code == VoldResponseCode.VolumeDiskRemoved) || 7334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat (code == VoldResponseCode.VolumeBadRemoval)) { 73422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>) 73522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>) 73622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>) 737a5250c93928e256738125b265e10c96c3575597eMike Lockwood String action = null; 7384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final String label = cooked[2]; 7394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final String path = cooked[3]; 7404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int major = -1; 7414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int minor = -1; 7424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 7434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 7444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String devComp = cooked[6].substring(1, cooked[6].length() -1); 7454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String[] devTok = devComp.split(":"); 7464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat major = Integer.parseInt(devTok[0]); 7474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat minor = Integer.parseInt(devTok[1]); 7484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 749a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to parse major/minor", ex); 7504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 7524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (code == VoldResponseCode.VolumeDiskInserted) { 7534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat new Thread() { 7545af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 7554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void run() { 7564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 7574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int rc; 758b104340496e3a531e26c8f428c808eca0e039f50San Mehat if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { 759a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, String.format("Insertion mount failed (%d)", rc)); 7604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 762a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Failed to mount media on insertion", ex); 7634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat }.start(); 7664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (code == VoldResponseCode.VolumeDiskRemoved) { 7674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 7684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * This event gets trumped if we're already in BAD_REMOVAL state 7694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 7704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) { 7714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return true; 7724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 774a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first"); 7754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 776a5250c93928e256738125b265e10c96c3575597eMike Lockwood sendStorageIntent(Environment.MEDIA_UNMOUNTED, path); 7774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 778a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed"); 7794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_REMOVED); 780a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_REMOVED; 7814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (code == VoldResponseCode.VolumeBadRemoval) { 782a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first"); 7834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 7844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 785a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_UNMOUNTED; 7864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 787a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal"); 7884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL); 789a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_BAD_REMOVAL; 7904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else { 791a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Unknown code {%d}", code)); 7924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 793a5250c93928e256738125b265e10c96c3575597eMike Lockwood 794a5250c93928e256738125b265e10c96c3575597eMike Lockwood if (action != null) { 795a5250c93928e256738125b265e10c96c3575597eMike Lockwood sendStorageIntent(action, path); 796a5250c93928e256738125b265e10c96c3575597eMike Lockwood } 79722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else { 79822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat return false; 79922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 8004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 8015f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler return true; 80222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 80322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 804207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void notifyVolumeStateChange(String label, String path, int oldState, int newState) { 8054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String vs = getVolumeState(path); 806a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChanged::" + vs); 8074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 808a5250c93928e256738125b265e10c96c3575597eMike Lockwood String action = null; 8097fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 810bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood if (oldState == VolumeState.Shared && newState != oldState) { 811a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent"); 812a5250c93928e256738125b265e10c96c3575597eMike Lockwood sendStorageIntent(Intent.ACTION_MEDIA_UNSHARED, path); 813bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood } 814bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood 8157fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat if (newState == VolumeState.Init) { 8167fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.NoMedia) { 8177fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat // NoMedia is handled via Disk Remove events 8187fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Idle) { 8195fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat /* 8205fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or 8215fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat * if we're in the process of enabling UMS 8225fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat */ 8234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!vs.equals( 8244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Environment.MEDIA_BAD_REMOVAL) && !vs.equals( 8254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Environment.MEDIA_NOFS) && !vs.equals( 8260eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) { 827a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable"); 8284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 829a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_UNMOUNTED; 8307fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 8317fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Pending) { 8327fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Checking) { 833a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking"); 8344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_CHECKING); 835a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_CHECKING; 8367fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Mounted) { 837a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted"); 8384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_MOUNTED); 839a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_MOUNTED; 8407fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Unmounting) { 841a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_EJECT; 8427fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Formatting) { 8437fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Shared) { 844a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted"); 8454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 8464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 847a5250c93928e256738125b265e10c96c3575597eMike Lockwood sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, path); 8484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 849a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared"); 8504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_SHARED); 851a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_SHARED; 852a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent"); 8537fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.SharedMnt) { 854a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Live shared mounts not supported yet!"); 8554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return; 8567fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else { 857a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Unhandled VolumeState {" + newState + "}"); 8587fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 8597fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 860a5250c93928e256738125b265e10c96c3575597eMike Lockwood if (action != null) { 861a5250c93928e256738125b265e10c96c3575597eMike Lockwood sendStorageIntent(action, path); 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 865207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doMountVolume(String path) { 866b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 867207e538350665cea00e1aa70b8094beca4a34e45San Mehat 868a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path); 869207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 870dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("volume", "mount", path); 871207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 872207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 873207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Mount failed for some reason 874207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 875a5250c93928e256738125b265e10c96c3575597eMike Lockwood String action = null; 876207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 877207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedNoMedia) { 878207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 879207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Attempt to mount but no media inserted 880207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 881b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedNoMedia; 882207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaBlank) { 883a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs"); 884207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 885207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Media is blank or does not contain a supported filesystem 886207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 887207e538350665cea00e1aa70b8094beca4a34e45San Mehat updatePublicVolumeState(path, Environment.MEDIA_NOFS); 888a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_NOFS; 889b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedMediaBlank; 890207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { 891a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state media corrupt"); 892207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 893207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Volume consistency check failed 894207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 895207e538350665cea00e1aa70b8094beca4a34e45San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE); 896a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_UNMOUNTABLE; 897b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedMediaCorrupt; 898207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 899b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 900207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 901207e538350665cea00e1aa70b8094beca4a34e45San Mehat 902207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 903207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Send broadcast intent (if required for the failure) 904207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 905a5250c93928e256738125b265e10c96c3575597eMike Lockwood if (action != null) { 906a5250c93928e256738125b265e10c96c3575597eMike Lockwood sendStorageIntent(action, path); 907207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 908207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 909207e538350665cea00e1aa70b8094beca4a34e45San Mehat 910207e538350665cea00e1aa70b8094beca4a34e45San Mehat return rc; 911207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 912207e538350665cea00e1aa70b8094beca4a34e45San Mehat 913c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu /* 914c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * If force is not set, we do not unmount if there are 915c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * processes holding references to the volume about to be unmounted. 916c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * If force is set, all the processes holding references need to be 917c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * killed via the ActivityManager before actually unmounting the volume. 918c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * This might even take a while and might be retried after timed delays 919c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * to make sure we dont end up in an instable state and kill some core 920c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * processes. 92113c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo * If removeEncryption is set, force is implied, and the system will remove any encryption 92213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo * mapping set on the volume when unmounting. 923c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu */ 92413c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo private int doUnmountVolume(String path, boolean force, boolean removeEncryption) { 92559443a673a736978361dc341f41ce4e9dae053a0San Mehat if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) { 926207e538350665cea00e1aa70b8094beca4a34e45San Mehat return VoldResponseCode.OpFailedVolNotMounted; 927207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 928aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 929aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 930aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 931aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 932aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 933aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 934aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 935aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 936aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 937c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu // Redundant probably. But no harm in updating state again. 938e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(false, false); 939207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 940dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final Command cmd = new Command("volume", "unmount", path); 941dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey if (removeEncryption) { 942dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey cmd.appendArg("force_and_revert"); 943dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } else if (force) { 944dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey cmd.appendArg("force"); 945dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } 946dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute(cmd); 947e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu // We unmounted the volume. None of the asec containers are available now. 948e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu synchronized (mAsecMountSet) { 949e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mAsecMountSet.clear(); 950e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu } 951b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationSucceeded; 952207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 953207e538350665cea00e1aa70b8094beca4a34e45San Mehat // Don't worry about mismatch in PackageManager since the 954207e538350665cea00e1aa70b8094beca4a34e45San Mehat // call back will handle the status changes any way. 955207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 956207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedVolNotMounted) { 957a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageNotMounted; 958d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else if (code == VoldResponseCode.OpFailedStorageBusy) { 959d970998b0d489774ad1c5b94b47d233912f00214San Mehat return StorageResultCode.OperationFailedStorageBusy; 960207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 961b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedInternalError; 962207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 963207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 964207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 965207e538350665cea00e1aa70b8094beca4a34e45San Mehat 966207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doFormatVolume(String path) { 967207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 968dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("volume", "format", path); 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) { 983dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 984a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root try { 985dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("volume", "shared", path, method); 986a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } catch (NativeDaemonConnectorException ex) { 987a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root Slog.e(TAG, "Failed to read response to volume shared " + path + " " + method); 988a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return false; 989a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } 990b104340496e3a531e26c8f428c808eca0e039f50San Mehat 991dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey if (event.getCode() == VoldResponseCode.ShareEnabledResult) { 992dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return event.getMessage().endsWith("enabled"); 993dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } else { 994dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return false; 995b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 996b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 997b104340496e3a531e26c8f428c808eca0e039f50San Mehat 998ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood private void notifyShareAvailabilityChange(final boolean avail) { 9994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 1000ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood mUmsAvailable = avail; 10014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for (int i = mListeners.size() -1; i >= 0; i--) { 10024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = mListeners.get(i); 10031f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat try { 1004b104340496e3a531e26c8f428c808eca0e039f50San Mehat bl.mListener.onUsbMassStorageConnectionChanged(avail); 10054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 1006a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener dead"); 10074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(i); 10081f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } catch (Exception ex) { 1009a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener failed", ex); 10101f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 10111f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 10124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 10137fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 1014207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (mBooted == true) { 10156a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat sendUmsIntent(avail); 10166a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } else { 10176a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat mSendUmsConnectedOnBoot = avail; 10181f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 10192fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat 10202fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat final String path = Environment.getExternalStorageDirectory().getPath(); 10212fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat if (avail == false && getVolumeState(path).equals(Environment.MEDIA_SHARED)) { 10222fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat /* 10232fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat * USB mass storage disconnected while enabled 10242fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat */ 10252fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat new Thread() { 10265af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 10272fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat public void run() { 10282fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat try { 10292fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat int rc; 1030a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Disabling UMS after cable disconnect"); 10312fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat doShareUnshareVolume(path, "ums", false); 10322fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { 1033a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format( 10342fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat "Failed to remount {%s} on UMS enabled-disconnect (%d)", 10352fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat path, rc)); 10362fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 10372fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } catch (Exception ex) { 1038a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Failed to mount media on UMS enabled-disconnect", ex); 10392fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 10402fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 10412fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat }.start(); 10422fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1045a5250c93928e256738125b265e10c96c3575597eMike Lockwood private void sendStorageIntent(String action, String path) { 1046a5250c93928e256738125b265e10c96c3575597eMike Lockwood Intent intent = new Intent(action, Uri.parse("file://" + path)); 1047a5250c93928e256738125b265e10c96c3575597eMike Lockwood // add StorageVolume extra 1048a5250c93928e256738125b265e10c96c3575597eMike Lockwood intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mVolumeMap.get(path)); 1049a5250c93928e256738125b265e10c96c3575597eMike Lockwood Slog.d(TAG, "sendStorageIntent " + intent); 10505ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1051a5250c93928e256738125b265e10c96c3575597eMike Lockwood } 1052a5250c93928e256738125b265e10c96c3575597eMike Lockwood 10536a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private void sendUmsIntent(boolean c) { 10545ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn mContext.sendBroadcastAsUser( 10555ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn new Intent((c ? Intent.ACTION_UMS_CONNECTED : Intent.ACTION_UMS_DISCONNECTED)), 10565ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn UserHandle.ALL); 10576a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } 10586a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat 1059207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void validatePermission(String perm) { 10604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) { 10614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new SecurityException(String.format("Requires %s permission", perm)); 10624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 10637fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 10647fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 10652f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood // Storage list XML tags 10662f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood private static final String TAG_STORAGE_LIST = "StorageList"; 10672f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood private static final String TAG_STORAGE = "storage"; 10682f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 106913fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio private void readStorageList() { 107013fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio Resources resources = mContext.getResources(); 107113fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio 10722f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood int id = com.android.internal.R.xml.storage_list; 10732f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood XmlResourceParser parser = resources.getXml(id); 10742f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood AttributeSet attrs = Xml.asAttributeSet(parser); 10752f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 10762f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood try { 10772f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood XmlUtils.beginDocument(parser, TAG_STORAGE_LIST); 10782f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood while (true) { 10792f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood XmlUtils.nextElement(parser); 10802f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 10812f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood String element = parser.getName(); 10822f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (element == null) break; 10832f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 10842f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (TAG_STORAGE.equals(element)) { 10852f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood TypedArray a = resources.obtainAttributes(attrs, 10862f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage); 10872f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 10882f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood CharSequence path = a.getText( 10892f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_mountPoint); 109013fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio int descriptionId = a.getResourceId( 109113fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio com.android.internal.R.styleable.Storage_storageDescription, -1); 10922f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood CharSequence description = a.getText( 10932f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_storageDescription); 10942f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood boolean primary = a.getBoolean( 10952f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_primary, false); 10962f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood boolean removable = a.getBoolean( 10972f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_removable, false); 10982f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood boolean emulated = a.getBoolean( 10992f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_emulated, false); 11002f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood int mtpReserve = a.getInt( 11012f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_mtpReserve, 0); 11028e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood boolean allowMassStorage = a.getBoolean( 11038e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood com.android.internal.R.styleable.Storage_allowMassStorage, false); 11047a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood // resource parser does not support longs, so XML value is in megabytes 11057a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood long maxFileSize = a.getInt( 11067a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood com.android.internal.R.styleable.Storage_maxFileSize, 0) * 1024L * 1024L; 11072f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 11082f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood Slog.d(TAG, "got storage path: " + path + " description: " + description + 11092f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood " primary: " + primary + " removable: " + removable + 11108e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood " emulated: " + emulated + " mtpReserve: " + mtpReserve + 11117a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood " allowMassStorage: " + allowMassStorage + 11127a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood " maxFileSize: " + maxFileSize); 11132f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (path == null || description == null) { 11142f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood Slog.e(TAG, "path or description is null in readStorageList"); 11152f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } else { 1116a5250c93928e256738125b265e10c96c3575597eMike Lockwood String pathString = path.toString(); 1117a5250c93928e256738125b265e10c96c3575597eMike Lockwood StorageVolume volume = new StorageVolume(pathString, 111813fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio descriptionId, removable, emulated, 11197a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood mtpReserve, allowMassStorage, maxFileSize); 11202f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (primary) { 11212f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (mPrimaryVolume == null) { 11222f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood mPrimaryVolume = volume; 11232f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } else { 11242f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood Slog.e(TAG, "multiple primary volumes in storage list"); 11252f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 11262f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 11272f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (mPrimaryVolume == volume) { 11282f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood // primay volume must be first 11292f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood mVolumes.add(0, volume); 11302f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } else { 11312f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood mVolumes.add(volume); 11322f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 1133a5250c93928e256738125b265e10c96c3575597eMike Lockwood mVolumeMap.put(pathString, volume); 11342f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 11352f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood a.recycle(); 11362f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 11372f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 11382f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } catch (XmlPullParserException e) { 11392f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood throw new RuntimeException(e); 11402f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } catch (IOException e) { 11412f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood throw new RuntimeException(e); 11422f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } finally { 1143fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood // compute storage ID for each volume 1144fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood int length = mVolumes.size(); 1145fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood for (int i = 0; i < length; i++) { 1146fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood mVolumes.get(i).setStorageId(i); 1147fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood } 11482f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood parser.close(); 11492f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 11502f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 11512f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1153207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Constructs a new MountService instance 1154207e538350665cea00e1aa70b8094beca4a34e45San Mehat * 1155207e538350665cea00e1aa70b8094beca4a34e45San Mehat * @param context Binder context for this service 1156207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 1157207e538350665cea00e1aa70b8094beca4a34e45San Mehat public MountService(Context context) { 1158207e538350665cea00e1aa70b8094beca4a34e45San Mehat mContext = context; 115913fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio readStorageList(); 11602f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 11612f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (mPrimaryVolume != null) { 11622f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood mExternalStoragePath = mPrimaryVolume.getPath(); 11632f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood mEmulateExternalStorage = mPrimaryVolume.isEmulated(); 11642f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (mEmulateExternalStorage) { 11652f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood Slog.d(TAG, "using emulated external storage"); 11662f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood mVolumeStates.put(mExternalStoragePath, Environment.MEDIA_MOUNTED); 11672f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 116803559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood } 116903559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood 1170207e538350665cea00e1aa70b8094beca4a34e45San Mehat // XXX: This will go away soon in favor of IMountServiceObserver 1171207e538350665cea00e1aa70b8094beca4a34e45San Mehat mPms = (PackageManagerService) ServiceManager.getService("package"); 1172207e538350665cea00e1aa70b8094beca4a34e45San Mehat 1173ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood IntentFilter filter = new IntentFilter(); 1174ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood filter.addAction(Intent.ACTION_BOOT_COMPLETED); 1175ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood // don't bother monitoring USB if mass storage is not supported on our primary volume 1176ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood if (mPrimaryVolume != null && mPrimaryVolume.allowMassStorage()) { 1177ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood filter.addAction(UsbManager.ACTION_USB_STATE); 1178ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood } 1179ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood mContext.registerReceiver(mBroadcastReceiver, filter, null, null); 1180207e538350665cea00e1aa70b8094beca4a34e45San Mehat 11815f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandlerThread = new HandlerThread("MountService"); 11825f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandlerThread.start(); 11835f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandler = new MountServiceHandler(mHandlerThread.getLooper()); 11845f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler 1185a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Add OBB Action Handler to MountService thread. 1186a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper()); 1187a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1188c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen /* 1189305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * Create the connection to vold with a maximum queue of twice the 1190305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * amount of containers we'd ever expect to have. This keeps an 1191305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * "asec list" from blocking a thread repeatedly. 1192305bcbf0c961840c4505770d084a1caacc074dbbKenny Root */ 1193470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25); 119451a573c76737733638c475f52e441c814e6645ccKenny Root 1195305bcbf0c961840c4505770d084a1caacc074dbbKenny Root Thread thread = new Thread(mConnector, VOLD_TAG); 1196207e538350665cea00e1aa70b8094beca4a34e45San Mehat thread.start(); 1197fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey 119807714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root // Add ourself to the Watchdog monitors if enabled. 119907714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root if (WATCHDOG_ENABLE) { 120007714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root Watchdog.getInstance().addMonitor(this); 120107714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root } 1202207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1203207e538350665cea00e1aa70b8094beca4a34e45San Mehat 1204207e538350665cea00e1aa70b8094beca4a34e45San Mehat /** 12054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Exposed API calls below here 12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12077fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 12084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void registerListener(IMountServiceListener listener) { 12094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 12104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = new MountServiceBinderListener(listener); 12114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 12124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat listener.asBinder().linkToDeath(bl, 0); 12134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.add(bl); 12144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 1215a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to link to listener death"); 12164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 12177fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void unregisterListener(IMountServiceListener listener) { 12214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 12224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for(MountServiceBinderListener bl : mListeners) { 12234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (bl.mListener == listener) { 12244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(mListeners.indexOf(bl)); 12255c25a2d338e9609d54e58cc1916c91cd8e9979abVairavan Srinivasan listener.asBinder().unlinkToDeath(bl, 0); 12264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return; 12274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 12284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12326ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu public void shutdown(final IMountShutdownObserver observer) { 12334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.SHUTDOWN); 12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1235a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Shutting down"); 12367fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood synchronized (mVolumeStates) { 12377fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood for (String path : mVolumeStates.keySet()) { 12387fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String state = mVolumeStates.get(path); 12397fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 12407fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state.equals(Environment.MEDIA_SHARED)) { 12417fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood /* 12427fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * If the media is currently shared, unshare it. 12437fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * XXX: This is still dangerous!. We should not 12447fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * be rebooting at *all* if UMS is enabled, since 12457fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * the UMS host could have dirty FAT cache entries 12467fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * yet to flush. 12477fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood */ 12487fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood setUsbMassStorageEnabled(false); 12497fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } else if (state.equals(Environment.MEDIA_CHECKING)) { 12507fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood /* 12517fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * If the media is being checked, then we need to wait for 12527fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * it to complete before being able to proceed. 12537fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood */ 12547fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood // XXX: @hackbod - Should we disable the ANR timer here? 12557fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood int retries = 30; 12567fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) { 12577fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood try { 12587fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Thread.sleep(1000); 12597fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } catch (InterruptedException iex) { 12607fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.e(TAG, "Interrupted while waiting for media", iex); 12617fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood break; 12627fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 12637fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood state = Environment.getExternalStorageState(); 12647fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 12657fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (retries == 0) { 12667fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.e(TAG, "Timed out waiting for media to check"); 12677fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 12684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 12697fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 12707fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state.equals(Environment.MEDIA_MOUNTED)) { 12717fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood // Post a unmount message. 12727fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood ShutdownCallBack ucb = new ShutdownCallBack(path, observer); 12737fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb)); 12747fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } else if (observer != null) { 12757fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood /* 12767fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * Observer is waiting for onShutDownComplete when we are done. 12777fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * Since nothing will be done send notification directly so shutdown 12787fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * sequence can continue. 12797fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood */ 12807fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood try { 12817fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood observer.onShutDownComplete(StorageResultCode.OperationSucceeded); 12827fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } catch (RemoteException e) { 12837fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.w(TAG, "RemoteException when shutting down"); 12847fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 12857fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 12865d0db4d356346bee68aec9a124df70dbaa9aaed1Johan Alfven } 12871f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12900eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private boolean getUmsEnabling() { 12910eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu synchronized (mListeners) { 12920eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu return mUmsEnabling; 12930eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 12940eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 12950eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 12960eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private void setUmsEnabling(boolean enable) { 12970eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu synchronized (mListeners) { 1298fc71125104650c61ab5b04f4c943de761d58cba6Tony Wu mUmsEnabling = enable; 12990eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 13000eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 13010eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 1302b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageConnected() { 1303207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 13047fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 13050eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (getUmsEnabling()) { 1306b104340496e3a531e26c8f428c808eca0e039f50San Mehat return true; 1307b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1308ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood synchronized (mListeners) { 1309ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood return mUmsAvailable; 1310ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood } 13114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13130eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu public void setUsbMassStorageEnabled(boolean enable) { 1314207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 13150eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 13160eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 13170eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // TODO: Add support for multiple share methods 1318b104340496e3a531e26c8f428c808eca0e039f50San Mehat 13190eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 13200eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * If the volume is mounted and we're enabling then unmount it 13210eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 13220eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String path = Environment.getExternalStorageDirectory().getPath(); 13230eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String vs = getVolumeState(path); 13240eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String method = "ums"; 13250eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (enable && vs.equals(Environment.MEDIA_MOUNTED)) { 13260eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Override for isUsbMassStorageEnabled() 13270eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu setUmsEnabling(enable); 13280eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true); 13290eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb)); 13300eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Clear override 13310eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu setUmsEnabling(false); 13320eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 13330eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 13340eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * If we disabled UMS then mount the volume 13350eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 13360eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (!enable) { 13370eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doShareUnshareVolume(path, method, enable); 13380eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (doMountVolume(path) != StorageResultCode.OperationSucceeded) { 1339a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to remount " + path + 13400eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu " after disabling share method " + method); 13410eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 13420eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * Even though the mount failed, the unshare didn't so don't indicate an error. 13430eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * The mountVolume() call will have set the storage state and sent the necessary 13440eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * broadcasts. 13450eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 13460eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 13470eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 13484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1350b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageEnabled() { 1351207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1352b104340496e3a531e26c8f428c808eca0e039f50San Mehat return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums"); 13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13549ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * @return state of the volume at the specified mount point 13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String getVolumeState(String mountPoint) { 13597fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood synchronized (mVolumeStates) { 13607fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String state = mVolumeStates.get(mountPoint); 13617fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state == null) { 13627fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume"); 136318db5c5690472f9da6ce2d580067307378675809Ken Sumrall if (SystemProperties.get("vold.encrypt_progress").length() != 0) { 136418db5c5690472f9da6ce2d580067307378675809Ken Sumrall state = Environment.MEDIA_REMOVED; 136518db5c5690472f9da6ce2d580067307378675809Ken Sumrall } else { 136618db5c5690472f9da6ce2d580067307378675809Ken Sumrall throw new IllegalArgumentException(); 136718db5c5690472f9da6ce2d580067307378675809Ken Sumrall } 13687fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 13694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 13707fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood return state; 13717fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1374e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root public boolean isExternalStorageEmulated() { 1375e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root return mEmulateExternalStorage; 1376e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root } 1377e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root 13784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int mountVolume(String path) { 13794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1381207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1382207e538350665cea00e1aa70b8094beca4a34e45San Mehat return doMountVolume(path); 13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 138513c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo public void unmountVolume(String path, boolean force, boolean removeEncryption) { 13864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1387207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13898a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu String volState = getVolumeState(path); 139013c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo if (DEBUG_UNMOUNT) { 139113c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo Slog.i(TAG, "Unmounting " + path 139213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo + " force = " + force 139313c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo + " removeEncryption = " + removeEncryption); 139413c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo } 13958a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (Environment.MEDIA_UNMOUNTED.equals(volState) || 13968a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_REMOVED.equals(volState) || 13978a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_SHARED.equals(volState) || 13988a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_UNMOUNTABLE.equals(volState)) { 13998a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // Media already unmounted or cannot be unmounted. 14008a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // TODO return valid return code when adding observer call back. 14018a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu return; 14028a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 140313c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo UnmountCallBack ucb = new UnmountCallBack(path, force, removeEncryption); 1404c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb)); 14054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int formatVolume(String path) { 14084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); 1409207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1411207e538350665cea00e1aa70b8094beca4a34e45San Mehat return doFormatVolume(path); 14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14133697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1414ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood public int[] getStorageUsers(String path) { 1415c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1416c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat waitForReady(); 1417c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat try { 1418dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final String[] r = NativeDaemonEvent.filterMessageList( 1419dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.executeForList("storage", "users", path), 1420dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey VoldResponseCode.StorageUsersListResult); 1421dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey 1422c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat // FMT: <pid> <process name> 1423c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat int[] data = new int[r.length]; 1424c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat for (int i = 0; i < r.length; i++) { 1425dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey String[] tok = r[i].split(" "); 1426c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat try { 1427c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat data[i] = Integer.parseInt(tok[0]); 1428c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } catch (NumberFormatException nfe) { 1429a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Error parsing pid %s", tok[0])); 1430c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return new int[0]; 1431c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1432c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1433c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return data; 1434c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } catch (NativeDaemonConnectorException e) { 1435a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to retrieve storage users list", e); 1436c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return new int[0]; 1437c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1438c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1439c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat 1440b104340496e3a531e26c8f428c808eca0e039f50San Mehat private void warnOnNotMounted() { 1441b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 1442a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "getSecureContainerList() called when storage not mounted"); 1443b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1444b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1445b104340496e3a531e26c8f428c808eca0e039f50San Mehat 14464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String[] getSecureContainerList() { 14474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 1448207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1449b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1450f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 14514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1452dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return NativeDaemonEvent.filterMessageList( 1453dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult); 14544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 14554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return new String[0]; 145602735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 14573697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 14583697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 14596dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root public int createSecureContainer(String id, int sizeMb, String fstype, String key, 14606dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root int ownerUid, boolean external) { 14614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_CREATE); 1462207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1463b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 14644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1465b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 14664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 14676dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root mConnector.execute("asec", "create", id, sizeMb, fstype, key, ownerUid, 14686dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root external ? "1" : "0"); 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 { 1487dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("asec", "finalize", id); 1488a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat /* 1489a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat * Finalization does a remount, so no need 1490a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat * to update mAsecMountSet 1491a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat */ 14926dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root } catch (NativeDaemonConnectorException e) { 14936dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root rc = StorageResultCode.OperationFailedInternalError; 14946dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root } 14956dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root return rc; 14966dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root } 14976dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root 14986dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root public int fixPermissionsSecureContainer(String id, int gid, String filename) { 14996dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root validatePermission(android.Manifest.permission.ASEC_CREATE); 15006dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root warnOnNotMounted(); 15016dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root 15026dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root int rc = StorageResultCode.OperationSucceeded; 15036dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root try { 15046dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root mConnector.execute("asec", "fixperms", id, gid, filename); 15056dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root /* 15066dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root * Fix permissions does a remount, so no need to update 15076dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root * mAsecMountSet 15086dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root */ 15094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1510b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 151102735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 15124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 15133697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 15143697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1515d970998b0d489774ad1c5b94b47d233912f00214San Mehat public int destroySecureContainer(String id, boolean force) { 15164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_DESTROY); 1517207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1518b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1519f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 1520aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 1521aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 1522aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 1523aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 1524aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 1525aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 1526aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 1527aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 1528b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 15294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1530dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final Command cmd = new Command("asec", "destroy", id); 1531dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey if (force) { 1532dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey cmd.appendArg("force"); 1533dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } 1534dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute(cmd); 15354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1536d970998b0d489774ad1c5b94b47d233912f00214San Mehat int code = e.getCode(); 1537d970998b0d489774ad1c5b94b47d233912f00214San Mehat if (code == VoldResponseCode.OpFailedStorageBusy) { 1538d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedStorageBusy; 1539d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else { 1540d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedInternalError; 1541d970998b0d489774ad1c5b94b47d233912f00214San Mehat } 154202735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1543a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1544a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (rc == StorageResultCode.OperationSucceeded) { 1545a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1546a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (mAsecMountSet.contains(id)) { 1547a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat mAsecMountSet.remove(id); 1548a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1549a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1550a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1551a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 15524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 15533697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 15549ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 15554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int mountSecureContainer(String id, String key, int ownerUid) { 15564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 1557207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1558b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 15594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1560a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1561a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (mAsecMountSet.contains(id)) { 1562a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageMounted; 1563a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1564a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1565a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1566b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 15674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1568dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("asec", "mount", id, key, ownerUid); 15694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1570f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root int code = e.getCode(); 1571f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root if (code != VoldResponseCode.OpFailedStorageBusy) { 1572f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root rc = StorageResultCode.OperationFailedInternalError; 1573f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root } 157402735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 15756cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 15766cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (rc == StorageResultCode.OperationSucceeded) { 15776cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 15786cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat mAsecMountSet.add(id); 15796cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 15806cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 15814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 15823697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 15833697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1584d970998b0d489774ad1c5b94b47d233912f00214San Mehat public int unmountSecureContainer(String id, boolean force) { 15854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 1586207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1587b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 15884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 15896cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 15906cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (!mAsecMountSet.contains(id)) { 1591a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageNotMounted; 15926cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 15936cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 15946cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 1595aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 1596aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 1597aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 1598aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 1599aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 1600aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 1601aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 1602aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 1603b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 16044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1605dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final Command cmd = new Command("asec", "unmount", id); 1606dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey if (force) { 1607dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey cmd.appendArg("force"); 1608dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } 1609dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute(cmd); 16104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1611d970998b0d489774ad1c5b94b47d233912f00214San Mehat int code = e.getCode(); 1612d970998b0d489774ad1c5b94b47d233912f00214San Mehat if (code == VoldResponseCode.OpFailedStorageBusy) { 1613d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedStorageBusy; 1614d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else { 1615d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedInternalError; 1616d970998b0d489774ad1c5b94b47d233912f00214San Mehat } 161702735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 16186cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 16196cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (rc == StorageResultCode.OperationSucceeded) { 16206cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 16216cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat mAsecMountSet.remove(id); 16226cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 16236cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 16244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 16259dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat } 16269dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat 16276cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat public boolean isSecureContainerMounted(String id) { 16286cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 16296cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat waitForReady(); 16306cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat warnOnNotMounted(); 16316cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 16326cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 16336cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat return mAsecMountSet.contains(id); 16346cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 16356cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 16366cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 16374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int renameSecureContainer(String oldId, String newId) { 16384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_RENAME); 1639207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1640b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 16414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1642a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 164385451ee15fdf6cae371dc3005441988c7d426401San Mehat /* 16449ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks * Because a mounted container has active internal state which cannot be 164585451ee15fdf6cae371dc3005441988c7d426401San Mehat * changed while active, we must ensure both ids are not currently mounted. 164685451ee15fdf6cae371dc3005441988c7d426401San Mehat */ 164785451ee15fdf6cae371dc3005441988c7d426401San Mehat if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) { 1648a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageMounted; 1649a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1650a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1651a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1652b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 16534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1654dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("asec", "rename", oldId, newId); 16554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1656b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 165702735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1658a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 16594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 166045f61040823d8c442838f75cde8760f236603daeSan Mehat } 166145f61040823d8c442838f75cde8760f236603daeSan Mehat 16624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String getSecureContainerPath(String id) { 16634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 1664207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1665b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1666f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 1667dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 16682d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat try { 1669dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("asec", "path", id); 1670dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event.checkCode(VoldResponseCode.AsecPathResult); 1671dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return event.getMessage(); 16722d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat } catch (NativeDaemonConnectorException e) { 16732d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat int code = e.getCode(); 16742d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat if (code == VoldResponseCode.OpFailedStorageNotFound) { 1675a20c8ef471666cf8b0dca91a8739ff18af1741a5Fredrik Helmer Slog.i(TAG, String.format("Container '%s' not found", id)); 1676a20c8ef471666cf8b0dca91a8739ff18af1741a5Fredrik Helmer return null; 167722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else { 16782d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat throw new IllegalStateException(String.format("Unexpected response code %d", code)); 167922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 168022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 168122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 1682292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn 1683292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn public String getSecureContainerFilesystemPath(String id) { 1684292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn validatePermission(android.Manifest.permission.ASEC_ACCESS); 1685292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn waitForReady(); 1686292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn warnOnNotMounted(); 1687292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn 1688dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 1689292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn try { 1690dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("asec", "fspath", id); 1691dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event.checkCode(VoldResponseCode.AsecPathResult); 1692dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return event.getMessage(); 1693292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn } catch (NativeDaemonConnectorException e) { 1694292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn int code = e.getCode(); 1695292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn if (code == VoldResponseCode.OpFailedStorageNotFound) { 1696292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn Slog.i(TAG, String.format("Container '%s' not found", id)); 1697292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn return null; 1698292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn } else { 1699292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn throw new IllegalStateException(String.format("Unexpected response code %d", code)); 1700292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn } 1701292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn } 1702292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn } 1703e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu 1704e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu public void finishMediaUpdate() { 1705e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE); 1706e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu } 170702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1708a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) { 1709a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (callerUid == android.os.Process.SYSTEM_UID) { 1710a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return true; 1711a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1712a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 171302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (packageName == null) { 171402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return false; 171502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 171602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1717f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn final int packageUid = mPms.getPackageUid(packageName, UserHandle.getUserId(callerUid)); 171802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 171902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (DEBUG_OBB) { 172002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root Slog.d(TAG, "packageName = " + packageName + ", packageUid = " + 172102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root packageUid + ", callerUid = " + callerUid); 172202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 172302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 172402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return callerUid == packageUid; 172502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 172602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 172702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root public String getMountedObbPath(String filename) { 1728af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (filename == null) { 1729af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalArgumentException("filename cannot be null"); 1730af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1731af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 173202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root waitForReady(); 173302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root warnOnNotMounted(); 173402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1735dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 173602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root try { 1737dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("obb", "path", filename); 1738dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event.checkCode(VoldResponseCode.AsecPathResult); 1739dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return event.getMessage(); 174002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } catch (NativeDaemonConnectorException e) { 174102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root int code = e.getCode(); 174202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (code == VoldResponseCode.OpFailedStorageNotFound) { 1743a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return null; 174402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } else { 174502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root throw new IllegalStateException(String.format("Unexpected response code %d", code)); 174602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 174702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 174802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 174902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 175002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root public boolean isObbMounted(String filename) { 1751af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (filename == null) { 1752af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalArgumentException("filename cannot be null"); 1753af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1754af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1755a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root synchronized (mObbMounts) { 1756af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return mObbPathToStateMap.containsKey(filename); 1757a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1758a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1759a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1760af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root public void mountObb(String filename, String key, IObbActionListener token, int nonce) 1761735de3b38abbd6564082a819377673ee593744a6Kenny Root throws RemoteException { 1762f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root if (filename == null) { 1763f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root throw new IllegalArgumentException("filename cannot be null"); 1764f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root } 1765f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root 1766af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (token == null) { 1767af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalArgumentException("token cannot be null"); 17682942391801b79816c5eb77d7ac94c4a65f26af48Kenny Root } 1769735de3b38abbd6564082a819377673ee593744a6Kenny Root 1770af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final int callerUid = Binder.getCallingUid(); 1771af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbState obbState = new ObbState(filename, callerUid, token, nonce); 1772af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbAction action = new MountObbAction(obbState, key); 1773a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 1774a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1775a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1776a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Send to OBB handler: " + action.toString()); 177702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 177802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1779af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root public void unmountObb(String filename, boolean force, IObbActionListener token, int nonce) 1780af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throws RemoteException { 1781f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root if (filename == null) { 1782f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root throw new IllegalArgumentException("filename cannot be null"); 1783f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root } 1784f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root 1785af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final int callerUid = Binder.getCallingUid(); 1786af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbState obbState = new ObbState(filename, callerUid, token, nonce); 1787af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbAction action = new UnmountObbAction(obbState, force); 1788a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 1789a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1790a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1791a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Send to OBB handler: " + action.toString()); 1792a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 179302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1794444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo @Override 1795444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo public int getEncryptionState() { 1796444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 1797444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo "no permission to access the crypt keeper"); 1798444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo 1799444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo waitForReady(); 1800444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo 1801dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 1802444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo try { 1803dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("cryptfs", "cryptocomplete"); 1804dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return Integer.parseInt(event.getMessage()); 1805444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo } catch (NumberFormatException e) { 1806444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo // Bad result - unexpected. 1807444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete"); 1808444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo return ENCRYPTION_STATE_ERROR_UNKNOWN; 1809444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo } catch (NativeDaemonConnectorException e) { 1810444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo // Something bad happened. 1811444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo Slog.w(TAG, "Error in communicating with cryptfs in validating"); 1812444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo return ENCRYPTION_STATE_ERROR_UNKNOWN; 1813444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo } 1814444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo } 1815444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo 1816444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo @Override 18175af0b916f850486cff4797355bf9e7dc3352fe00Jason parks public int decryptStorage(String password) { 1818f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (TextUtils.isEmpty(password)) { 1819f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks throw new IllegalArgumentException("password cannot be empty"); 18205af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 18215af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 18228888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 18238888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks "no permission to access the crypt keeper"); 18245af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 18255af0b916f850486cff4797355bf9e7dc3352fe00Jason parks waitForReady(); 18265af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 18275af0b916f850486cff4797355bf9e7dc3352fe00Jason parks if (DEBUG_EVENTS) { 18285af0b916f850486cff4797355bf9e7dc3352fe00Jason parks Slog.i(TAG, "decrypting storage..."); 18295af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 18305af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 1831dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 18325af0b916f850486cff4797355bf9e7dc3352fe00Jason parks try { 1833dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("cryptfs", "checkpw", password); 18349ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 1835da6aedf716bfdd40148823fb63d666d34b7b425eFredrik Roubert final int code = Integer.parseInt(event.getMessage()); 18369ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks if (code == 0) { 18379ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks // Decrypt was successful. Post a delayed message before restarting in order 18389ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks // to let the UI to clear itself 18399ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks mHandler.postDelayed(new Runnable() { 18409ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks public void run() { 184131c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey try { 1842dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("cryptfs", "restart"); 184331c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey } catch (NativeDaemonConnectorException e) { 184431c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey Slog.e(TAG, "problem executing in background", e); 184531c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey } 18469ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks } 1847f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks }, 1000); // 1 second 18489ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks } 18499ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 18509ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks return code; 18515af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } catch (NativeDaemonConnectorException e) { 18525af0b916f850486cff4797355bf9e7dc3352fe00Jason parks // Decryption failed 18535af0b916f850486cff4797355bf9e7dc3352fe00Jason parks return e.getCode(); 18545af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 18555af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 18565af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 185756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks public int encryptStorage(String password) { 1858f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (TextUtils.isEmpty(password)) { 1859f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks throw new IllegalArgumentException("password cannot be empty"); 186056aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 186156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 18628888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 18638888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks "no permission to access the crypt keeper"); 186456aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 186556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks waitForReady(); 186656aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 186756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks if (DEBUG_EVENTS) { 18688888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks Slog.i(TAG, "encrypting storage..."); 186956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 187056aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 187156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks try { 1872dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("cryptfs", "enablecrypto", "inplace", password); 187356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } catch (NativeDaemonConnectorException e) { 187456aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks // Encryption failed 187556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks return e.getCode(); 187656aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 187756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 187856aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks return 0; 187956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 188056aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 1881f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks public int changeEncryptionPassword(String password) { 1882f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (TextUtils.isEmpty(password)) { 1883f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks throw new IllegalArgumentException("password cannot be empty"); 1884f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 1885f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1886f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 1887f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks "no permission to access the crypt keeper"); 1888f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1889f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks waitForReady(); 1890f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1891f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (DEBUG_EVENTS) { 1892f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks Slog.i(TAG, "changing encryption password..."); 1893f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 1894f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1895dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 1896f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks try { 1897dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("cryptfs", "changepw", password); 1898dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return Integer.parseInt(event.getMessage()); 1899f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } catch (NativeDaemonConnectorException e) { 1900f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks // Encryption failed 1901f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks return e.getCode(); 1902f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 1903f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 1904f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 190532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate /** 190632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate * Validate a user-supplied password string with cryptfs 190732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate */ 190832418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate @Override 190932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate public int verifyEncryptionPassword(String password) throws RemoteException { 191032418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate // Only the system process is permitted to validate passwords 191132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { 191232418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate throw new SecurityException("no permission to access the crypt keeper"); 191332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } 191432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 191532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 191632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate "no permission to access the crypt keeper"); 191732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 191832418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate if (TextUtils.isEmpty(password)) { 191932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate throw new IllegalArgumentException("password cannot be empty"); 192032418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } 192132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 192232418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate waitForReady(); 192332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 192432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate if (DEBUG_EVENTS) { 192532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate Slog.i(TAG, "validating encryption password..."); 192632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } 192732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 1928dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 192932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate try { 1930dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("cryptfs", "verifypw", password); 1931dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey Slog.i(TAG, "cryptfs verifypw => " + event.getMessage()); 1932dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return Integer.parseInt(event.getMessage()); 193332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } catch (NativeDaemonConnectorException e) { 193432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate // Encryption failed 193532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate return e.getCode(); 193632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } 193732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } 193832418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 19392f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood public Parcelable[] getVolumeList() { 19402f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood synchronized(mVolumes) { 19412f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood int size = mVolumes.size(); 19422f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood Parcelable[] result = new Parcelable[size]; 19432f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood for (int i = 0; i < size; i++) { 19442f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood result[i] = mVolumes.get(i); 19458fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood } 19468fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood return result; 19478fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood } 19488fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood } 19498fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood 1950af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private void addObbStateLocked(ObbState obbState) throws RemoteException { 1951af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IBinder binder = obbState.getBinder(); 1952af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root List<ObbState> obbStates = mObbMounts.get(binder); 19535919ac6b4188285324646772501ef4b97b353cf4Kenny Root 1954af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates == null) { 1955af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates = new ArrayList<ObbState>(); 1956af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.put(binder, obbStates); 1957af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 1958af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root for (final ObbState o : obbStates) { 1959af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (o.filename.equals(obbState.filename)) { 1960af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalStateException("Attempt to add ObbState twice. " 1961af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + "This indicates an error in the MountService logic."); 19625919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 19635919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 196402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 196502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1966af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates.add(obbState); 1967af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 1968af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState.link(); 1969af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (RemoteException e) { 1970af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root /* 1971af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * The binder died before we could link it, so clean up our state 1972af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * and return failure. 1973af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root */ 1974af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates.remove(obbState); 1975af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.isEmpty()) { 1976af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.remove(binder); 197705105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 19785919ac6b4188285324646772501ef4b97b353cf4Kenny Root 1979af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Rethrow the error so mountObb can get it 1980af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw e; 198102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 1982af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1983af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbPathToStateMap.put(obbState.filename, obbState); 1984a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 198502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1986af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private void removeObbStateLocked(ObbState obbState) { 1987af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IBinder binder = obbState.getBinder(); 1988af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStates = mObbMounts.get(binder); 1989af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates != null) { 1990af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.remove(obbState)) { 1991af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState.unlink(); 1992af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1993af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.isEmpty()) { 1994af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.remove(binder); 1995af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 199638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 1997af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1998af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbPathToStateMap.remove(obbState.filename); 199938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 200038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2001a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private class ObbActionHandler extends Handler { 2002a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean mBound = false; 2003480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root private final List<ObbAction> mActions = new LinkedList<ObbAction>(); 2004a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2005a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbActionHandler(Looper l) { 2006a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(l); 2007a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2008a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2009a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 2010a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleMessage(Message msg) { 2011a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root switch (msg.what) { 2012a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_RUN_ACTION: { 2013480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root final ObbAction action = (ObbAction) msg.obj; 2014a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2015a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2016a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString()); 2017a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2018a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // If a bind was already initiated we don't really 2019a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // need to do anything. The pending install 2020a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // will be processed later on. 2021a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!mBound) { 2022a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // If this is the only one pending we might 2023a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // have to bind to the service again. 2024a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!connectToService()) { 2025a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Failed to bind to media container service"); 2026a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 2027a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return; 2028a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2029a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2030735de3b38abbd6564082a819377673ee593744a6Kenny Root 2031735de3b38abbd6564082a819377673ee593744a6Kenny Root mActions.add(action); 2032a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 2033a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2034a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_BOUND: { 2035a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2036a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_BOUND"); 2037a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (msg.obj != null) { 2038a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContainerService = (IMediaContainerService) msg.obj; 2039a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2040a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mContainerService == null) { 2041a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Something seriously wrong. Bail out 2042a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Cannot bind to media container service"); 2043a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root for (ObbAction action : mActions) { 2044a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Indicate service bind error 2045a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 2046a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2047a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.clear(); 2048a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else if (mActions.size() > 0) { 2049480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root final ObbAction action = mActions.get(0); 2050a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (action != null) { 2051a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.execute(this); 2052a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2053a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 2054a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Should never happen ideally. 2055a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.w(TAG, "Empty queue"); 2056a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2057a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 2058a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2059a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_RECONNECT: { 2060a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2061a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_RECONNECT"); 2062a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() > 0) { 2063a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mBound) { 2064a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root disconnectService(); 2065a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2066a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!connectToService()) { 2067a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Failed to bind to media container service"); 2068a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root for (ObbAction action : mActions) { 2069a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Indicate service bind error 2070a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 2071a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2072a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.clear(); 2073a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2074a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2075a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 2076a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2077a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_UNBIND: { 2078a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2079a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_UNBIND"); 2080a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2081a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Delete pending install 2082a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() > 0) { 2083a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.remove(0); 2084a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2085a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() == 0) { 2086a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mBound) { 2087a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root disconnectService(); 2088a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2089a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 2090a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // There are more pending requests in queue. 2091a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Just post MCS_BOUND message to trigger processing 2092a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // of next pending install. 2093a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND); 2094a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2095a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 2096a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2097af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root case OBB_FLUSH_MOUNT_STATE: { 2098af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final String path = (String) msg.obj; 2099af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2100af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 2101af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.i(TAG, "Flushing all OBB state for path " + path); 2102af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2103af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 2104af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>(); 2105af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2106af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Iterator<Entry<String, ObbState>> i = 2107af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbPathToStateMap.entrySet().iterator(); 2108af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (i.hasNext()) { 2109af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Entry<String, ObbState> obbEntry = i.next(); 2110af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2111af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root /* 2112af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * If this entry's source file is in the volume path 2113af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * that got unmounted, remove it because it's no 2114af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * longer valid. 2115af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root */ 2116af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbEntry.getKey().startsWith(path)) { 2117af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStatesToRemove.add(obbEntry.getValue()); 2118af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2119af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2120af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2121af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root for (final ObbState obbState : obbStatesToRemove) { 2122af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 2123af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.i(TAG, "Removing state for " + obbState.filename); 2124af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2125af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root removeObbStateLocked(obbState); 2126af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2127af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 2128af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState.token.onObbResult(obbState.filename, obbState.nonce, 2129af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root OnObbStateChangeListener.UNMOUNTED); 2130af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (RemoteException e) { 2131af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.i(TAG, "Couldn't send unmount notification for OBB: " 2132af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + obbState.filename); 2133af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2134af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2135af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2136af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root break; 2137af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 213802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 213902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 214002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2141a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean connectToService() { 2142a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2143a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Trying to bind to DefaultContainerService"); 2144a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2145a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); 2146a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) { 2147a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mBound = true; 2148a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return true; 214902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 2150a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return false; 2151a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2152a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2153a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private void disconnectService() { 2154a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContainerService = null; 2155a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mBound = false; 2156a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContext.unbindService(mDefContainerConn); 215702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 215802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 215902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2160a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root abstract class ObbAction { 2161a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int MAX_RETRIES = 3; 2162a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private int mRetries; 216302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2164a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbState mObbState; 2165a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2166a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbAction(ObbState obbState) { 2167a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbState = obbState; 216802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 216902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2170a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void execute(ObbActionHandler handler) { 2171a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root try { 2172a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2173444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo Slog.i(TAG, "Starting to execute action: " + toString()); 2174a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mRetries++; 2175a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mRetries > MAX_RETRIES) { 2176a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); 2177480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 2178a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleError(); 2179a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return; 2180a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 2181a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleExecute(); 2182a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2183a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Posting install MCS_UNBIND"); 2184a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 2185a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2186a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } catch (RemoteException e) { 2187a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2188a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Posting install MCS_RECONNECT"); 2189a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT); 2190a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } catch (Exception e) { 2191a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2192a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.d(TAG, "Error handling OBB action", e); 2193a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleError(); 219417eb6fb07cc6965f09c51adc70b3c291f57a784aKenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 219502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 2196a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 219702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 219805105f7abe02b2dff91d6260b3628c8b97816babKenny Root abstract void handleExecute() throws RemoteException, IOException; 2199a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root abstract void handleError(); 220038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 220138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root protected ObbInfo getObbInfo() throws IOException { 220238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root ObbInfo obbInfo; 220338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root try { 220438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root obbInfo = mContainerService.getObbInfo(mObbState.filename); 220538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } catch (RemoteException e) { 220638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for " 220738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root + mObbState.filename); 220838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root obbInfo = null; 220938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 221038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root if (obbInfo == null) { 221138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root throw new IOException("Couldn't read OBB file: " + mObbState.filename); 221238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 221338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return obbInfo; 221438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 221538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2216af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root protected void sendNewStatusOrIgnore(int status) { 2217af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (mObbState == null || mObbState.token == null) { 2218af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2219af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2220af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 222138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root try { 2222af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbState.token.onObbResult(mObbState.filename, mObbState.nonce, status); 222338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } catch (RemoteException e) { 222438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged"); 222538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 222638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2227a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2228a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2229a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class MountObbAction extends ObbAction { 2230444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo private final String mKey; 2231a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2232a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root MountObbAction(ObbState obbState, String key) { 2233a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(obbState); 2234a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mKey = key; 2235a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2236a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 22375af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 2238735de3b38abbd6564082a819377673ee593744a6Kenny Root public void handleExecute() throws IOException, RemoteException { 2239af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root waitForReady(); 2240af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root warnOnNotMounted(); 2241af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 224238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root final ObbInfo obbInfo = getObbInfo(); 224338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2244af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mObbState.callerUid)) { 2245af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename 2246af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + " which is owned by " + obbInfo.packageName); 2247af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); 2248af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2249af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2250af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2251af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final boolean isMounted; 2252af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 2253af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root isMounted = mObbPathToStateMap.containsKey(obbInfo.filename); 2254af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2255af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (isMounted) { 2256af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename); 2257af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED); 2258af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2259af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2260af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 226138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root /* 2262af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * The filename passed in might not be the canonical name, so just 2263af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * set the filename to the canonicalized version. 226438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root */ 2265af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbState.filename = obbInfo.filename; 226638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2267af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final String hashedKey; 2268af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (mKey == null) { 2269af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root hashedKey = "none"; 2270af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 2271af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 22723b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 22733b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 22743b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt, 22753b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE); 22763b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root SecretKey key = factory.generateSecret(ks); 22773b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root BigInteger bi = new BigInteger(key.getEncoded()); 22783b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root hashedKey = bi.toString(16); 2279af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NoSuchAlgorithmException e) { 22803b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root Slog.e(TAG, "Could not load PBKDF2 algorithm", e); 22813b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 22823b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root return; 22833b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root } catch (InvalidKeySpecException e) { 22843b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e); 22853b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 2286af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 228738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2288a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2289a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2290af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int rc = StorageResultCode.OperationSucceeded; 2291af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 2292dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute( 2293dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey "obb", "mount", mObbState.filename, hashedKey, mObbState.callerUid); 2294af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NativeDaemonConnectorException e) { 2295af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int code = e.getCode(); 2296af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (code != VoldResponseCode.OpFailedStorageBusy) { 2297af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedInternalError; 2298a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2299af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2300a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2301af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (rc == StorageResultCode.OperationSucceeded) { 2302af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 2303af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.d(TAG, "Successfully mounted OBB " + mObbState.filename); 230438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2305af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 2306af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root addObbStateLocked(mObbState); 2307a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 230838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2309af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED); 231002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } else { 231105105f7abe02b2dff91d6260b3628c8b97816babKenny Root Slog.e(TAG, "Couldn't mount OBB file: " + rc); 2312a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2313af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT); 231402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 231502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 231602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 23175af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 2318a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleError() { 2319af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 232002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 2321a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2322a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 2323a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public String toString() { 2324a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root StringBuilder sb = new StringBuilder(); 2325a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("MountObbAction{"); 2326a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("filename="); 2327a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.filename); 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"); 2332af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny 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 } 2337a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2338a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2339a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class UnmountObbAction extends ObbAction { 2340444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo private final boolean mForceUnmount; 2341a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2342a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root UnmountObbAction(ObbState obbState, boolean force) { 2343a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(obbState); 2344a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mForceUnmount = force; 2345a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2346a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 23475af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 234838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root public void handleExecute() throws IOException { 2349af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root waitForReady(); 2350af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root warnOnNotMounted(); 2351af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 235238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root final ObbInfo obbInfo = getObbInfo(); 2353a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2354af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbState obbState; 235538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root synchronized (mObbMounts) { 2356af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState = mObbPathToStateMap.get(obbInfo.filename); 2357af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 235838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2359af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbState == null) { 2360af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED); 2361af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2362a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2363a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2364af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbState.callerUid != mObbState.callerUid) { 2365af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Permission denied attempting to unmount OBB " + obbInfo.filename 2366af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + " (owned by " + obbInfo.packageName + ")"); 2367af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); 2368af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2369af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2370a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2371af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbState.filename = obbInfo.filename; 237238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2373af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int rc = StorageResultCode.OperationSucceeded; 2374af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 2375dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final Command cmd = new Command("obb", "unmount", mObbState.filename); 2376dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey if (mForceUnmount) { 2377dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey cmd.appendArg("force"); 2378dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } 2379dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute(cmd); 2380af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NativeDaemonConnectorException e) { 2381af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int code = e.getCode(); 2382af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (code == VoldResponseCode.OpFailedStorageBusy) { 2383af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedStorageBusy; 2384af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else if (code == VoldResponseCode.OpFailedStorageNotFound) { 2385af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // If it's not mounted then we've already won. 2386af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationSucceeded; 2387af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 2388af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedInternalError; 2389a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2390a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 239138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2392af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (rc == StorageResultCode.OperationSucceeded) { 2393af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 2394af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root removeObbStateLocked(obbState); 2395af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 239638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2397af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED); 239838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } else { 2399af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Could not mount OBB: " + mObbState.filename); 2400af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT); 240138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2402a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2403a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 24045af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 2405a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleError() { 2406af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 2407a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2408a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2409a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 2410a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public String toString() { 2411a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root StringBuilder sb = new StringBuilder(); 2412a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("UnmountObbAction{"); 2413a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("filename="); 2414a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.filename != null ? mObbState.filename : "null"); 2415a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",force="); 2416a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mForceUnmount); 2417a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",callerUid="); 2418a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.callerUid); 2419a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",token="); 2420a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.token != null ? mObbState.token.toString() : "null"); 2421735de3b38abbd6564082a819377673ee593744a6Kenny Root sb.append(",binder="); 2422af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sb.append(mObbState.token != null ? mObbState.getBinder().toString() : "null"); 2423a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append('}'); 2424a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return sb.toString(); 2425a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 242602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 242738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 242838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root @Override 242938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 243038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { 243138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root pw.println("Permission Denial: can't dump ActivityManager from from pid=" 243238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() 243338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root + " without permission " + android.Manifest.permission.DUMP); 243438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return; 243538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 243638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 243738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root synchronized (mObbMounts) { 2438af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(" mObbMounts:"); 243938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2440af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet().iterator(); 2441af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (binders.hasNext()) { 2442af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Entry<IBinder, List<ObbState>> e = binders.next(); 2443af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" Key="); pw.println(e.getKey().toString()); 2444af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStates = e.getValue(); 244538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root for (final ObbState obbState : obbStates) { 2446af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" "); pw.println(obbState.toString()); 244738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 244838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2449af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2450af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(""); 2451af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(" mObbPathToStateMap:"); 2452af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator(); 2453af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (maps.hasNext()) { 2454af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Entry<String, ObbState> e = maps.next(); 2455af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" "); pw.print(e.getKey()); 2456af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" -> "); pw.println(e.getValue().toString()); 2457af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 245838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 24594161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root 24604161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root pw.println(""); 24614161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root 24624161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root synchronized (mVolumes) { 24634161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root pw.println(" mVolumes:"); 24644161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root 24654161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root final int N = mVolumes.size(); 24664161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root for (int i = 0; i < N; i++) { 24674161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root final StorageVolume v = mVolumes.get(i); 24684161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root pw.print(" "); 24694161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root pw.println(v.toString()); 24704161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root } 24714161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root } 2472470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt 2473470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt pw.println(); 2474470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt pw.println(" mConnection:"); 2475470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt mConnector.dump(fd, pw, args); 247638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 24779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2478fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey /** {@inheritDoc} */ 2479fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey public void monitor() { 2480fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey if (mConnector != null) { 2481fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey mConnector.monitor(); 2482fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey } 2483fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey } 2484fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey} 2485