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 19b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport static android.content.pm.PackageManager.PERMISSION_GRANTED; 20c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 218888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parksimport android.Manifest; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver; 23a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ComponentName; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter; 27a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ServiceConnection; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager; 29b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport android.content.pm.UserInfo; 3002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.content.res.ObbInfo; 312f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.Resources; 322f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.TypedArray; 332f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.XmlResourceParser; 34ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwoodimport android.hardware.usb.UsbManager; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri; 3602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.os.Binder; 37a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.Environment; 38b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport android.os.Environment.UserEnvironment; 39c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Handler; 405f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.HandlerThread; 41a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.IBinder; 425f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.Looper; 43c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Message; 444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehatimport android.os.RemoteException; 45fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapuimport android.os.ServiceManager; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties; 47f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport android.os.UserHandle; 48a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountService; 49a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountServiceListener; 50a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountShutdownObserver; 51a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IObbActionListener; 52af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Rootimport android.os.storage.OnObbStateChangeListener; 53a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.StorageResultCode; 542f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.os.storage.StorageVolume; 55f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parksimport android.text.TextUtils; 562f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.util.AttributeSet; 57a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehatimport android.util.Slog; 582f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.util.Xml; 592f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 60b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.internal.app.IMediaContainerService; 614fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkeyimport com.android.internal.util.Preconditions; 62b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.internal.util.XmlUtils; 63b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.server.NativeDaemonConnector.Command; 64b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.server.am.ActivityManagerService; 65b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.server.pm.PackageManagerService; 66b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.server.pm.UserManagerService; 67b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.google.android.collect.Lists; 68b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.google.android.collect.Maps; 69b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 702f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport org.xmlpull.v1.XmlPullParserException; 71a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 72b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport java.io.File; 7338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.FileDescriptor; 7405105f7abe02b2dff91d6260b3628c8b97816babKenny Rootimport java.io.IOException; 7538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.PrintWriter; 763b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.math.BigInteger; 77735de3b38abbd6564082a819377673ee593744a6Kenny Rootimport java.security.NoSuchAlgorithmException; 783b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.InvalidKeySpecException; 793b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.KeySpec; 8022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehatimport java.util.ArrayList; 81a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.HashMap; 826cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehatimport java.util.HashSet; 8338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Iterator; 84a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.LinkedList; 85a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.List; 86a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.Map; 8738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Map.Entry; 8851a573c76737733638c475f52e441c814e6645ccKenny Rootimport java.util.concurrent.CountDownLatch; 8951a573c76737733638c475f52e441c814e6645ccKenny Rootimport java.util.concurrent.TimeUnit; 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 913b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKey; 923b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKeyFactory; 933b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.spec.PBEKeySpec; 943b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 96b104340496e3a531e26c8f428c808eca0e039f50San Mehat * MountService implements back-end services for platform storage 97b104340496e3a531e26c8f428c808eca0e039f50San Mehat * management. 98b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @hide - Applications should use android.os.storage.StorageManager 99b104340496e3a531e26c8f428c808eca0e039f50San Mehat * to access the MountService. 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 101fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkeyclass MountService extends IMountService.Stub 102fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey implements INativeDaemonConnectorCallbacks, Watchdog.Monitor { 1035af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 104b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // TODO: listen for user creation/deletion 105b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 106b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private static final boolean LOCAL_LOGD = true; 107b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private static final boolean DEBUG_UNMOUNT = true; 108b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private static final boolean DEBUG_EVENTS = true; 109b7db2726e91f1d9480359d0f83b9cb7769906b34Kenny Root private static final boolean DEBUG_OBB = false; 11002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 11107714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root // Disable this since it messes up long-running cryptfs operations. 11207714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root private static final boolean WATCHDOG_ENABLE = false; 11307714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String TAG = "MountService"; 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 116305bcbf0c961840c4505770d084a1caacc074dbbKenny Root private static final String VOLD_TAG = "VoldConnector"; 117305bcbf0c961840c4505770d084a1caacc074dbbKenny Root 118cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root /** Maximum number of ASEC containers allowed to be mounted. */ 119cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root private static final int MAX_CONTAINERS = 250; 120cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root 1214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Internal vold volume state constants 1234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 1247fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat class VolumeState { 1257fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Init = -1; 1267fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int NoMedia = 0; 1277fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Idle = 1; 1287fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Pending = 2; 1297fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Checking = 3; 1307fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Mounted = 4; 1317fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Unmounting = 5; 1327fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Formatting = 6; 1337fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Shared = 7; 1347fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int SharedMnt = 8; 1357fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 1367fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 1374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Internal vold response code constants 1394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 14022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat class VoldResponseCode { 1414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 100 series - Requestion action was initiated; expect another reply 1434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * before proceeding with a new command. 1444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 14522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeListResult = 110; 14622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int AsecListResult = 111; 147c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat public static final int StorageUsersListResult = 112; 14822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 200 series - Requestion action has been successfully completed. 1514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 1524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int ShareStatusResult = 210; 15322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int AsecPathResult = 211; 1544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int ShareEnabledResult = 212; 15522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 400 series - Command was accepted, but the requested action 1584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * did not take place. 1594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 1604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedNoMedia = 401; 1614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedMediaBlank = 402; 1624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedMediaCorrupt = 403; 1634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedVolNotMounted = 404; 164d970998b0d489774ad1c5b94b47d233912f00214San Mehat public static final int OpFailedStorageBusy = 405; 1652d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat public static final int OpFailedStorageNotFound = 406; 1664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 600 series - Unsolicited broadcasts. 1694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 17022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeStateChange = 605; 17122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeDiskInserted = 630; 17222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeDiskRemoved = 631; 17322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeBadRemoval = 632; 17422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 17522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 176b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private Context mContext; 177b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private NativeDaemonConnector mConnector; 178b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 179b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private final Object mVolumesLock = new Object(); 180b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 181b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey /** When defined, base template for user-specific {@link StorageVolume}. */ 182b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private StorageVolume mEmulatedTemplate; 183b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 184b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // @GuardedBy("mVolumesLock") 185b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private final ArrayList<StorageVolume> mVolumes = Lists.newArrayList(); 186b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey /** Map from path to {@link StorageVolume} */ 187b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // @GuardedBy("mVolumesLock") 188b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private final HashMap<String, StorageVolume> mVolumesByPath = Maps.newHashMap(); 189b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey /** Map from path to state */ 190b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // @GuardedBy("mVolumesLock") 191b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private final HashMap<String, String> mVolumeStates = Maps.newHashMap(); 192b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 193b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private volatile boolean mSystemReady = false; 194b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private PackageManagerService mPms; 1964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private boolean mUmsEnabling; 197ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood private boolean mUmsAvailable = false; 1980eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Used as a lock for methods that register/unregister listeners. 1990eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu final private ArrayList<MountServiceBinderListener> mListeners = 2000eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu new ArrayList<MountServiceBinderListener>(); 20151a573c76737733638c475f52e441c814e6645ccKenny Root private CountDownLatch mConnectedSignal = new CountDownLatch(1); 20251a573c76737733638c475f52e441c814e6645ccKenny Root private CountDownLatch mAsecsScanned = new CountDownLatch(1); 2036a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private boolean mSendUmsConnectedOnBoot = false; 204fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapu 2056cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat /** 2066cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat * Private hash of currently mounted secure containers. 2070eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * Used as a lock in methods to manipulate secure containers. 2086cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat */ 2090eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu final private HashSet<String> mAsecMountSet = new HashSet<String>(); 2106cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 21102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root /** 2123b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * The size of the crypto algorithm key in bits for OBB files. Currently 2133b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * Twofish is used which takes 128-bit keys. 2143b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root */ 2153b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128; 2163b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 2173b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root /** 2183b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * The number of times to run SHA1 in the PBKDF2 function for OBB files. 2193b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * 1024 is reasonably secure and not too slow. 2203b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root */ 2213b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root private static final int PBKDF2_HASH_ROUNDS = 1024; 2223b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 2233b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root /** 224a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * Mounted OBB tracking information. Used to track the current state of all 225a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * OBBs. 226a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root */ 227735de3b38abbd6564082a819377673ee593744a6Kenny Root final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>(); 2284fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 2294fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey /** Map from raw paths to {@link ObbState}. */ 230a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>(); 231a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 232a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class ObbState implements IBinder.DeathRecipient { 2334fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey public ObbState(String rawPath, String canonicalPath, int callingUid, 2344fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey IObbActionListener token, int nonce) { 2354fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey this.rawPath = rawPath; 2364fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey this.canonicalPath = canonicalPath.toString(); 2374fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 2384fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final int userId = UserHandle.getUserId(callingUid); 2394fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey this.ownerPath = buildObbPath(canonicalPath, userId, false); 2404fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey this.voldPath = buildObbPath(canonicalPath, userId, true); 2414fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 2424fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey this.ownerGid = UserHandle.getSharedAppGid(callingUid); 243af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root this.token = token; 244af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root this.nonce = nonce; 245a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 246a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2474fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final String rawPath; 2484fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final String canonicalPath; 2494fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final String ownerPath; 2504fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final String voldPath; 251a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2524fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final int ownerGid; 253a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 254af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Token of remote Binder caller 255af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IObbActionListener token; 256af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 257af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Identifier to pass back to the token 258af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final int nonce; 259a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 260735de3b38abbd6564082a819377673ee593744a6Kenny Root public IBinder getBinder() { 261735de3b38abbd6564082a819377673ee593744a6Kenny Root return token.asBinder(); 262735de3b38abbd6564082a819377673ee593744a6Kenny Root } 263735de3b38abbd6564082a819377673ee593744a6Kenny Root 264a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 265a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void binderDied() { 266a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbAction action = new UnmountObbAction(this, true); 267a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 268735de3b38abbd6564082a819377673ee593744a6Kenny Root } 269a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2705919ac6b4188285324646772501ef4b97b353cf4Kenny Root public void link() throws RemoteException { 2715919ac6b4188285324646772501ef4b97b353cf4Kenny Root getBinder().linkToDeath(this, 0); 2725919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 2735919ac6b4188285324646772501ef4b97b353cf4Kenny Root 2745919ac6b4188285324646772501ef4b97b353cf4Kenny Root public void unlink() { 275735de3b38abbd6564082a819377673ee593744a6Kenny Root getBinder().unlinkToDeath(this, 0); 276a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 27738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 27838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root @Override 27938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root public String toString() { 28038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root StringBuilder sb = new StringBuilder("ObbState{"); 2814fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append("rawPath=").append(rawPath); 2824fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append(",canonicalPath=").append(canonicalPath); 2834fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append(",ownerPath=").append(ownerPath); 2844fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append(",voldPath=").append(voldPath); 2854fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append(",ownerGid=").append(ownerGid); 2864fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append(",token=").append(token); 2874fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append(",binder=").append(getBinder()); 28838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append('}'); 28938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return sb.toString(); 29038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 291a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 292a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 293a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // OBB Action Handler 294a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private ObbActionHandler mObbActionHandler; 295a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 296a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // OBB action handler messages 297a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_RUN_ACTION = 1; 298a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_BOUND = 2; 299a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_UNBIND = 3; 300a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_RECONNECT = 4; 301af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private static final int OBB_FLUSH_MOUNT_STATE = 5; 302a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 303a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root /* 304a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * Default Container Service information 30502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root */ 306a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName( 307a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService"); 308a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 309a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection(); 310a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 311a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class DefaultContainerConnection implements ServiceConnection { 312a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void onServiceConnected(ComponentName name, IBinder service) { 313a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 314a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "onServiceConnected"); 315a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service); 316a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs)); 317a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 318a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 319a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void onServiceDisconnected(ComponentName name) { 320a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 321a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "onServiceDisconnected"); 322a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 323a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root }; 324a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 325a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Used in the ObbActionHandler 326a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private IMediaContainerService mContainerService = null; 32702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 32802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root // Handler messages 329c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_PM_UPDATE = 1; 330c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_PM_DONE = 2; 331c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_MS = 3; 332b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private static final int H_SYSTEM_READY = 4; 333b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 334c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int RETRY_UNMOUNT_DELAY = 30; // in ms 335c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int MAX_UNMOUNT_RETRIES = 4; 336c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 337c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu class UnmountCallBack { 33805105f7abe02b2dff91d6260b3628c8b97816babKenny Root final String path; 33905105f7abe02b2dff91d6260b3628c8b97816babKenny Root final boolean force; 34013c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo final boolean removeEncryption; 341c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu int retries; 342c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 34313c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo UnmountCallBack(String path, boolean force, boolean removeEncryption) { 344c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu retries = 0; 345c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu this.path = path; 346c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu this.force = force; 34713c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo this.removeEncryption = removeEncryption; 348c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 3490eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3500eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu void handleFinished() { 351a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path); 35213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo doUnmountVolume(path, true, removeEncryption); 3530eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 3540eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 3550eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3560eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu class UmsEnableCallBack extends UnmountCallBack { 35705105f7abe02b2dff91d6260b3628c8b97816babKenny Root final String method; 3580eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3590eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu UmsEnableCallBack(String path, String method, boolean force) { 36013c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo super(path, force, false); 3610eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu this.method = method; 3620eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 3630eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3640eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu @Override 3650eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu void handleFinished() { 3660eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu super.handleFinished(); 3670eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doShareUnshareVolume(path, method, true); 3680eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 369c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 370c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 3716ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu class ShutdownCallBack extends UnmountCallBack { 3726ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu IMountShutdownObserver observer; 3736ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu ShutdownCallBack(String path, IMountShutdownObserver observer) { 37413c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo super(path, true, false); 3756ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu this.observer = observer; 3766ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3776ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3786ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu @Override 3796ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu void handleFinished() { 38013c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo int ret = doUnmountVolume(path, true, removeEncryption); 3816ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (observer != null) { 3826ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu try { 3836ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu observer.onShutDownComplete(ret); 3846ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } catch (RemoteException e) { 385a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "RemoteException when shutting down"); 3866ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3876ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3886ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3896ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3906ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3915f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler class MountServiceHandler extends Handler { 392c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>(); 393e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu boolean mUpdatingStatus = false; 3946ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3955f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler MountServiceHandler(Looper l) { 3965f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler super(l); 3975f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler } 3985f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler 3995af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 400c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu public void handleMessage(Message msg) { 401c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu switch (msg.what) { 402c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_PM_UPDATE: { 403a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_UPDATE"); 404c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = (UnmountCallBack) msg.obj; 405c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu mForceUnmounts.add(ucb); 406a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, " registered = " + mUpdatingStatus); 4076ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Register only if needed. 408e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu if (!mUpdatingStatus) { 409a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Updating external media status on PackageManager"); 410e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mUpdatingStatus = true; 411e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(false, true); 412c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 413c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 414c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 415c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_PM_DONE: { 416a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_DONE"); 417a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Updated status. Processing requests"); 418e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mUpdatingStatus = false; 4196ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int size = mForceUnmounts.size(); 4206ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int sizeArr[] = new int[size]; 4216ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int sizeArrN = 0; 4227af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Kill processes holding references first 4237af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ActivityManagerService ams = (ActivityManagerService) 4247af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ServiceManager.getService("activity"); 4256ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu for (int i = 0; i < size; i++) { 4266ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu UnmountCallBack ucb = mForceUnmounts.get(i); 4276ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu String path = ucb.path; 4286ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu boolean done = false; 4296ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (!ucb.force) { 430c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu done = true; 431c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } else { 4326ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int pids[] = getStorageUsers(path); 4336ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (pids == null || pids.length == 0) { 4346ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu done = true; 4356ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } else { 4366ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Eliminate system process here? 437648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn ams.killPids(pids, "unmount media", true); 4387af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Confirm if file references have been freed. 4397af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu pids = getStorageUsers(path); 4407af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu if (pids == null || pids.length == 0) { 4417af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu done = true; 442c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 443c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 444c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 4457af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) { 4467af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Retry again 4477af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu Slog.i(TAG, "Retrying to kill storage users again"); 4487af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.sendMessageDelayed( 4497af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.obtainMessage(H_UNMOUNT_PM_DONE, 4507af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ucb.retries++), 4517af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu RETRY_UNMOUNT_DELAY); 452c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } else { 4536ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (ucb.retries >= MAX_UNMOUNT_RETRIES) { 4547af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu Slog.i(TAG, "Failed to unmount media inspite of " + 4557af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu MAX_UNMOUNT_RETRIES + " retries. Forcibly killing processes now"); 4566ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 4577af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu sizeArr[sizeArrN++] = i; 4587af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS, 4597af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ucb)); 460c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 461c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 4626ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Remove already processed elements from list. 4636ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu for (int i = (sizeArrN-1); i >= 0; i--) { 4646ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu mForceUnmounts.remove(sizeArr[i]); 4656ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 466c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 467c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 468b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey case H_UNMOUNT_MS: { 469a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_MS"); 470c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = (UnmountCallBack) msg.obj; 4710eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu ucb.handleFinished(); 472c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 473c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 474b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey case H_SYSTEM_READY: { 475b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey try { 476b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey handleSystemReady(); 477b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } catch (Exception ex) { 478b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Slog.e(TAG, "Boot-time mount exception", ex); 479b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 480b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey break; 481b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 482c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 483c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 484c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu }; 485b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 486b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private final HandlerThread mHandlerThread; 487b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private final Handler mHandler; 488c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 48951a573c76737733638c475f52e441c814e6645ccKenny Root void waitForAsecScan() { 49051a573c76737733638c475f52e441c814e6645ccKenny Root waitForLatch(mAsecsScanned); 49151a573c76737733638c475f52e441c814e6645ccKenny Root } 49251a573c76737733638c475f52e441c814e6645ccKenny Root 493207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void waitForReady() { 49451a573c76737733638c475f52e441c814e6645ccKenny Root waitForLatch(mConnectedSignal); 49551a573c76737733638c475f52e441c814e6645ccKenny Root } 49651a573c76737733638c475f52e441c814e6645ccKenny Root 49751a573c76737733638c475f52e441c814e6645ccKenny Root private void waitForLatch(CountDownLatch latch) { 49851a573c76737733638c475f52e441c814e6645ccKenny Root if (latch == null) { 49951a573c76737733638c475f52e441c814e6645ccKenny Root return; 50051a573c76737733638c475f52e441c814e6645ccKenny Root } 50151a573c76737733638c475f52e441c814e6645ccKenny Root 50251a573c76737733638c475f52e441c814e6645ccKenny Root for (;;) { 50351a573c76737733638c475f52e441c814e6645ccKenny Root try { 50451a573c76737733638c475f52e441c814e6645ccKenny Root if (latch.await(5000, TimeUnit.MILLISECONDS)) { 505207e538350665cea00e1aa70b8094beca4a34e45San Mehat return; 50651a573c76737733638c475f52e441c814e6645ccKenny Root } else { 50751a573c76737733638c475f52e441c814e6645ccKenny Root Slog.w(TAG, "Thread " + Thread.currentThread().getName() 50851a573c76737733638c475f52e441c814e6645ccKenny Root + " still waiting for MountService ready..."); 509207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 51051a573c76737733638c475f52e441c814e6645ccKenny Root } catch (InterruptedException e) { 51151a573c76737733638c475f52e441c814e6645ccKenny Root Slog.w(TAG, "Interrupt while waiting for MountService to be ready."); 512207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 513207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 5141f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 51502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 516b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private void handleSystemReady() { 517b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // Snapshot current volume states since it's not safe to call into vold 518b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // while holding locks. 519b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final HashMap<String, String> snapshot; 520b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 521b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey snapshot = new HashMap<String, String>(mVolumeStates); 522b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 52391c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 524b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey for (Map.Entry<String, String> entry : snapshot.entrySet()) { 525b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final String path = entry.getKey(); 526b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final String state = entry.getValue(); 52722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 528b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (state.equals(Environment.MEDIA_UNMOUNTED)) { 529b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey int rc = doMountVolume(path); 530b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (rc != StorageResultCode.OperationSucceeded) { 531b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Slog.e(TAG, String.format("Boot-time mount failed (%d)", 532b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey rc)); 533b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 534b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } else if (state.equals(Environment.MEDIA_SHARED)) { 535c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen /* 536b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * Bootstrap UMS enabled state since vold indicates 537b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * the volume is shared (runtime restart while ums enabled) 538c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen */ 539b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey notifyVolumeStateChange(null, path, VolumeState.NoMedia, 540b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey VolumeState.Shared); 541b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 542b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 543b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 544b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // Push mounted state for all emulated storage 545b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 546b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey for (StorageVolume volume : mVolumes) { 547b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (volume.isEmulated()) { 548b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED); 549c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen } 550b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 551b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 55284338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood 553b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey /* 554b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * If UMS was connected on boot, send the connected event 555b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * now that we're up. 556b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey */ 557b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (mSendUmsConnectedOnBoot) { 558b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey sendUmsIntent(true); 559b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mSendUmsConnectedOnBoot = false; 560b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 561b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 5626a254403235196692b1769d2fe281b0852c0cc25San Mehat 563b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() { 564b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey @Override 565b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey public void onReceive(Context context, Intent intent) { 566b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 567b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (userId == -1) return; 568b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final UserHandle user = new UserHandle(userId); 569b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 570b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final String action = intent.getAction(); 571b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (Intent.ACTION_USER_ADDED.equals(action)) { 572b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 573b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey createEmulatedVolumeForUserLocked(user); 574b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 575b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 576b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 577b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 578b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final List<StorageVolume> toRemove = Lists.newArrayList(); 579b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey for (StorageVolume volume : mVolumes) { 580b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (user.equals(volume.getOwner())) { 581b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey toRemove.add(volume); 582fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } 583207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 584b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey for (StorageVolume volume : toRemove) { 585b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey removeVolumeLocked(volume); 586b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 587b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 591b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 592b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { 593b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey @Override 594b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey public void onReceive(Context context, Intent intent) { 595b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey boolean available = (intent.getBooleanExtra(UsbManager.USB_CONNECTED, false) && 596b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey intent.getBooleanExtra(UsbManager.USB_FUNCTION_MASS_STORAGE, false)); 597b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey notifyShareAvailabilityChange(available); 598b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 599b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey }; 600b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 6014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private final class MountServiceBinderListener implements IBinder.DeathRecipient { 6024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final IMountServiceListener mListener; 60391c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 6044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener(IMountServiceListener listener) { 6054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListener = listener; 60602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 60791c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 60891c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 6094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void binderDied() { 610a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!"); 611a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root synchronized (mListeners) { 6124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(this); 6134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListener.asBinder().unlinkToDeath(this, 0); 61491c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 61591c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 61691c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 61791c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 6180eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private void doShareUnshareVolume(String path, String method, boolean enable) { 6194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat // TODO: Add support for multiple share methods 6204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!method.equals("ums")) { 6214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new IllegalArgumentException(String.format("Method %s not supported", method)); 6227fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 625dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("volume", enable ? "share" : "unshare", path, method); 6264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 627a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to share/unshare", e); 62822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 631b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private void updatePublicVolumeState(StorageVolume volume, String state) { 632b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final String path = volume.getPath(); 633b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final String oldState; 634b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 6357fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood oldState = mVolumeStates.put(path, state); 6367fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 637b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 6387fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state.equals(oldState)) { 6397fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.w(TAG, String.format("Duplicate state transition (%s -> %s) for %s", 6407fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood state, state, path)); 641b104340496e3a531e26c8f428c808eca0e039f50San Mehat return; 642b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 643af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 6447fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.d(TAG, "volume state changed for " + path + " (" + oldState + " -> " + state + ")"); 6457fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 646b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // Tell PackageManager about changes to primary volume state, but only 647b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // when not emulated. 648b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (volume.isPrimary() && !volume.isEmulated()) { 649b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (Environment.MEDIA_UNMOUNTED.equals(state)) { 650b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mPms.updateExternalMediaStatus(false, false); 6517fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 652b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey /* 653b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * Some OBBs might have been unmounted when this volume was 654b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * unmounted, so send a message to the handler to let it know to 655b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * remove those from the list of mounted OBBS. 656b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey */ 657b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage( 658b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey OBB_FLUSH_MOUNT_STATE, path)); 659b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } else if (Environment.MEDIA_MOUNTED.equals(state)) { 660b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mPms.updateExternalMediaStatus(true, false); 66103559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood } 6628a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 663b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 6644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 6654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for (int i = mListeners.size() -1; i >= 0; i--) { 6664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = mListeners.get(i); 6674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 668b104340496e3a531e26c8f428c808eca0e039f50San Mehat bl.mListener.onStorageStateChanged(path, oldState, state); 6694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 670a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener dead"); 6714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(i); 6724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 673a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener failed", ex); 6744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 67922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat /** 68022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * Callback from NativeDaemonConnector 68122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat */ 68222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public void onDaemonConnected() { 6835b77dab23469273d41f9c530d947ac055765e6eaSan Mehat /* 6845b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * Since we'll be calling back into the NativeDaemonConnector, 6855b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * we need to do our work in a new thread. 6865b77dab23469273d41f9c530d947ac055765e6eaSan Mehat */ 68751a573c76737733638c475f52e441c814e6645ccKenny Root new Thread("MountService#onDaemonConnected") { 6885af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 6897fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public void run() { 6905b77dab23469273d41f9c530d947ac055765e6eaSan Mehat /** 6915b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * Determine media state and UMS detection status 6925b77dab23469273d41f9c530d947ac055765e6eaSan Mehat */ 6937fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat try { 694dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final String[] vols = NativeDaemonEvent.filterMessageList( 695dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.executeForList("volume", "list"), 696dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey VoldResponseCode.VolumeListResult); 6975b77dab23469273d41f9c530d947ac055765e6eaSan Mehat for (String volstr : vols) { 6985b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String[] tok = volstr.split(" "); 6995b77dab23469273d41f9c530d947ac055765e6eaSan Mehat // FMT: <label> <mountpoint> <state> 7007fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String path = tok[1]; 7017fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String state = Environment.MEDIA_REMOVED; 7027fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 703b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume volume; 704b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 705b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey volume = mVolumesByPath.get(path); 706b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 707b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 7085b77dab23469273d41f9c530d947ac055765e6eaSan Mehat int st = Integer.parseInt(tok[2]); 7095b77dab23469273d41f9c530d947ac055765e6eaSan Mehat if (st == VolumeState.NoMedia) { 7105b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_REMOVED; 7115b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Idle) { 712207e538350665cea00e1aa70b8094beca4a34e45San Mehat state = Environment.MEDIA_UNMOUNTED; 7135b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Mounted) { 7145b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_MOUNTED; 715a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Media already mounted on daemon connection"); 7165b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Shared) { 7175b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_SHARED; 718a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Media shared on daemon connection"); 7195b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else { 7205b77dab23469273d41f9c530d947ac055765e6eaSan Mehat throw new Exception(String.format("Unexpected state %d", st)); 7217fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 7227fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 7237fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state != null) { 7247fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state); 725b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, state); 7267fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 727c2a39471642e31d7350910612e40d078b825173aSan Mehat } 7285b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } catch (Exception e) { 729a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Error processing initial volume state", e); 730b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume primary = getPrimaryPhysicalVolume(); 731b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (primary != null) { 732b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(primary, Environment.MEDIA_REMOVED); 733b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 7347fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 7357fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 736207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 7379ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks * Now that we've done our initialization, release 738207e538350665cea00e1aa70b8094beca4a34e45San Mehat * the hounds! 739207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 74051a573c76737733638c475f52e441c814e6645ccKenny Root mConnectedSignal.countDown(); 74151a573c76737733638c475f52e441c814e6645ccKenny Root mConnectedSignal = null; 74251a573c76737733638c475f52e441c814e6645ccKenny Root 74351a573c76737733638c475f52e441c814e6645ccKenny Root // Let package manager load internal ASECs. 74451a573c76737733638c475f52e441c814e6645ccKenny Root mPms.scanAvailableAsecs(); 74551a573c76737733638c475f52e441c814e6645ccKenny Root 74651a573c76737733638c475f52e441c814e6645ccKenny Root // Notify people waiting for ASECs to be scanned that it's done. 74751a573c76737733638c475f52e441c814e6645ccKenny Root mAsecsScanned.countDown(); 74851a573c76737733638c475f52e441c814e6645ccKenny Root mAsecsScanned = null; 7497fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 7507fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat }.start(); 7517fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 7527fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 75322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat /** 75422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * Callback from NativeDaemonConnector 75522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat */ 75622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public boolean onEvent(int code, String raw, String[] cooked) { 7578a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (DEBUG_EVENTS) { 7588a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu StringBuilder builder = new StringBuilder(); 7598a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append("onEvent::"); 7608a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" raw= " + raw); 7618a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (cooked != null) { 7628a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" cooked = " ); 7638a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu for (String str : cooked) { 7648a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" " + str); 7658a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 7668a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 767a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, builder.toString()); 7688a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 76922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat if (code == VoldResponseCode.VolumeStateChange) { 7704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 7714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * One of the volumes we're managing has changed state. 7724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Format: "NNN Volume <label> <path> state changed 7734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * from <old_#> (<old_str>) to <new_#> (<new_str>)" 7744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 77522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat notifyVolumeStateChange( 77622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat cooked[2], cooked[3], Integer.parseInt(cooked[7]), 77722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat Integer.parseInt(cooked[10])); 7784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if ((code == VoldResponseCode.VolumeDiskInserted) || 7794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat (code == VoldResponseCode.VolumeDiskRemoved) || 7804270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat (code == VoldResponseCode.VolumeBadRemoval)) { 78122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>) 78222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>) 78322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>) 784a5250c93928e256738125b265e10c96c3575597eMike Lockwood String action = null; 7854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final String label = cooked[2]; 7864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final String path = cooked[3]; 7874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int major = -1; 7884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int minor = -1; 7894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 7904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 7914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String devComp = cooked[6].substring(1, cooked[6].length() -1); 7924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String[] devTok = devComp.split(":"); 7934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat major = Integer.parseInt(devTok[0]); 7944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat minor = Integer.parseInt(devTok[1]); 7954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 796a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to parse major/minor", ex); 7974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 799b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume volume; 800b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final String state; 801b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 802b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey volume = mVolumesByPath.get(path); 803b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey state = mVolumeStates.get(path); 804b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 805b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 8064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (code == VoldResponseCode.VolumeDiskInserted) { 8074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat new Thread() { 8085af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 8094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void run() { 8104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 8114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int rc; 812b104340496e3a531e26c8f428c808eca0e039f50San Mehat if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { 813a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, String.format("Insertion mount failed (%d)", rc)); 8144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 8154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 816a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Failed to mount media on insertion", ex); 8174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 8184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 8194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat }.start(); 8204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (code == VoldResponseCode.VolumeDiskRemoved) { 8214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 8224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * This event gets trumped if we're already in BAD_REMOVAL state 8234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 8244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) { 8254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return true; 8264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 8274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 828a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first"); 829b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED); 830b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey sendStorageIntent(Environment.MEDIA_UNMOUNTED, volume, UserHandle.ALL); 8314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 832a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed"); 833b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_REMOVED); 834a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_REMOVED; 8354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (code == VoldResponseCode.VolumeBadRemoval) { 836a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first"); 8374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 838b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED); 839a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_UNMOUNTED; 8404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 841a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal"); 842b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_BAD_REMOVAL); 843a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_BAD_REMOVAL; 8444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else { 845a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Unknown code {%d}", code)); 8464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 847a5250c93928e256738125b265e10c96c3575597eMike Lockwood 848a5250c93928e256738125b265e10c96c3575597eMike Lockwood if (action != null) { 849b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey sendStorageIntent(action, volume, UserHandle.ALL); 850a5250c93928e256738125b265e10c96c3575597eMike Lockwood } 85122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else { 85222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat return false; 85322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 8544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 8555f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler return true; 85622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 85722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 858207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void notifyVolumeStateChange(String label, String path, int oldState, int newState) { 859b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume volume; 860b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final String state; 861b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 862b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey volume = mVolumesByPath.get(path); 863b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey state = getVolumeState(path); 864b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 865b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 866b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChange::" + state); 8674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 868a5250c93928e256738125b265e10c96c3575597eMike Lockwood String action = null; 8697fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 870bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood if (oldState == VolumeState.Shared && newState != oldState) { 871a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent"); 872b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey sendStorageIntent(Intent.ACTION_MEDIA_UNSHARED, volume, UserHandle.ALL); 873bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood } 874bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood 8757fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat if (newState == VolumeState.Init) { 8767fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.NoMedia) { 8777fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat // NoMedia is handled via Disk Remove events 8787fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Idle) { 8795fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat /* 8805fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or 8815fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat * if we're in the process of enabling UMS 8825fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat */ 883b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (!state.equals( 884b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Environment.MEDIA_BAD_REMOVAL) && !state.equals( 885b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Environment.MEDIA_NOFS) && !state.equals( 8860eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) { 887a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable"); 888b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED); 889a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_UNMOUNTED; 8907fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 8917fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Pending) { 8927fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Checking) { 893a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking"); 894b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_CHECKING); 895a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_CHECKING; 8967fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Mounted) { 897a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted"); 898b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED); 899a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_MOUNTED; 9007fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Unmounting) { 901a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_EJECT; 9027fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Formatting) { 9037fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Shared) { 904a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted"); 9054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 906b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED); 907b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL); 9084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 909a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared"); 910b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_SHARED); 911a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_SHARED; 912a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent"); 9137fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.SharedMnt) { 914a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Live shared mounts not supported yet!"); 9154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return; 9167fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else { 917a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Unhandled VolumeState {" + newState + "}"); 9187fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 9197fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 920a5250c93928e256738125b265e10c96c3575597eMike Lockwood if (action != null) { 921b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey sendStorageIntent(action, volume, UserHandle.ALL); 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 925207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doMountVolume(String path) { 926b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 927207e538350665cea00e1aa70b8094beca4a34e45San Mehat 928b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume volume; 929b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 930b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey volume = mVolumesByPath.get(path); 931b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 932b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 933a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path); 934207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 935dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("volume", "mount", path); 936207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 937207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 938207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Mount failed for some reason 939207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 940a5250c93928e256738125b265e10c96c3575597eMike Lockwood String action = null; 941207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 942207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedNoMedia) { 943207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 944207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Attempt to mount but no media inserted 945207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 946b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedNoMedia; 947207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaBlank) { 948a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs"); 949207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 950207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Media is blank or does not contain a supported filesystem 951207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 952b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_NOFS); 953a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_NOFS; 954b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedMediaBlank; 955207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { 956a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state media corrupt"); 957207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 958207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Volume consistency check failed 959207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 960b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTABLE); 961a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_UNMOUNTABLE; 962b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedMediaCorrupt; 963207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 964b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 965207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 966207e538350665cea00e1aa70b8094beca4a34e45San Mehat 967207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 968207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Send broadcast intent (if required for the failure) 969207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 970a5250c93928e256738125b265e10c96c3575597eMike Lockwood if (action != null) { 971b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey sendStorageIntent(action, volume, UserHandle.ALL); 972207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 973207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 974207e538350665cea00e1aa70b8094beca4a34e45San Mehat 975207e538350665cea00e1aa70b8094beca4a34e45San Mehat return rc; 976207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 977207e538350665cea00e1aa70b8094beca4a34e45San Mehat 978c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu /* 979c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * If force is not set, we do not unmount if there are 980c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * processes holding references to the volume about to be unmounted. 981c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * If force is set, all the processes holding references need to be 982c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * killed via the ActivityManager before actually unmounting the volume. 983c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * This might even take a while and might be retried after timed delays 984c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * to make sure we dont end up in an instable state and kill some core 985c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * processes. 98613c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo * If removeEncryption is set, force is implied, and the system will remove any encryption 98713c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo * mapping set on the volume when unmounting. 988c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu */ 98913c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo private int doUnmountVolume(String path, boolean force, boolean removeEncryption) { 99059443a673a736978361dc341f41ce4e9dae053a0San Mehat if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) { 991207e538350665cea00e1aa70b8094beca4a34e45San Mehat return VoldResponseCode.OpFailedVolNotMounted; 992207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 993aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 994aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 995aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 996aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 997aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 998aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 999aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 1000aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 1001aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 1002c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu // Redundant probably. But no harm in updating state again. 1003e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(false, false); 1004207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 1005dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final Command cmd = new Command("volume", "unmount", path); 1006dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey if (removeEncryption) { 1007dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey cmd.appendArg("force_and_revert"); 1008dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } else if (force) { 1009dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey cmd.appendArg("force"); 1010dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } 1011dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute(cmd); 1012e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu // We unmounted the volume. None of the asec containers are available now. 1013e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu synchronized (mAsecMountSet) { 1014e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mAsecMountSet.clear(); 1015e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu } 1016b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationSucceeded; 1017207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 1018207e538350665cea00e1aa70b8094beca4a34e45San Mehat // Don't worry about mismatch in PackageManager since the 1019207e538350665cea00e1aa70b8094beca4a34e45San Mehat // call back will handle the status changes any way. 1020207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 1021207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedVolNotMounted) { 1022a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageNotMounted; 1023d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else if (code == VoldResponseCode.OpFailedStorageBusy) { 1024d970998b0d489774ad1c5b94b47d233912f00214San Mehat return StorageResultCode.OperationFailedStorageBusy; 1025207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 1026b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedInternalError; 1027207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1028207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1029207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1030207e538350665cea00e1aa70b8094beca4a34e45San Mehat 1031207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doFormatVolume(String path) { 1032207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 1033dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("volume", "format", path); 1034b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationSucceeded; 1035207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 1036207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 1037207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedNoMedia) { 1038b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedNoMedia; 1039207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { 1040b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedMediaCorrupt; 1041207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 1042b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedInternalError; 1043207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1044207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1045207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1046207e538350665cea00e1aa70b8094beca4a34e45San Mehat 1047b104340496e3a531e26c8f428c808eca0e039f50San Mehat private boolean doGetVolumeShared(String path, String method) { 1048dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 1049a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root try { 1050dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("volume", "shared", path, method); 1051a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } catch (NativeDaemonConnectorException ex) { 1052a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root Slog.e(TAG, "Failed to read response to volume shared " + path + " " + method); 1053a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return false; 1054a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } 1055b104340496e3a531e26c8f428c808eca0e039f50San Mehat 1056dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey if (event.getCode() == VoldResponseCode.ShareEnabledResult) { 1057dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return event.getMessage().endsWith("enabled"); 1058dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } else { 1059dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return false; 1060b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1061b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1062b104340496e3a531e26c8f428c808eca0e039f50San Mehat 1063ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood private void notifyShareAvailabilityChange(final boolean avail) { 10644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 1065ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood mUmsAvailable = avail; 10664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for (int i = mListeners.size() -1; i >= 0; i--) { 10674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = mListeners.get(i); 10681f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat try { 1069b104340496e3a531e26c8f428c808eca0e039f50San Mehat bl.mListener.onUsbMassStorageConnectionChanged(avail); 10704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 1071a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener dead"); 10724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(i); 10731f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } catch (Exception ex) { 1074a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener failed", ex); 10751f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 10761f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 10774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 10787fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 1079b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (mSystemReady == true) { 10806a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat sendUmsIntent(avail); 10816a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } else { 10826a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat mSendUmsConnectedOnBoot = avail; 10831f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 10842fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat 1085b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume primary = getPrimaryPhysicalVolume(); 1086b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (avail == false && primary != null 1087b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey && Environment.MEDIA_SHARED.equals(getVolumeState(primary.getPath()))) { 1088b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final String path = primary.getPath(); 10892fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat /* 10902fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat * USB mass storage disconnected while enabled 10912fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat */ 10922fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat new Thread() { 10935af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 10942fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat public void run() { 10952fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat try { 10962fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat int rc; 1097a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Disabling UMS after cable disconnect"); 10982fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat doShareUnshareVolume(path, "ums", false); 10992fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { 1100a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format( 11012fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat "Failed to remount {%s} on UMS enabled-disconnect (%d)", 11022fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat path, rc)); 11032fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 11042fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } catch (Exception ex) { 1105a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Failed to mount media on UMS enabled-disconnect", ex); 11062fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 11072fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 11082fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat }.start(); 11092fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1112b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private void sendStorageIntent(String action, StorageVolume volume, UserHandle user) { 1113b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final Intent intent = new Intent(action, Uri.parse("file://" + volume.getPath())); 1114b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, volume); 1115b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Slog.d(TAG, "sendStorageIntent " + intent + " to " + user); 1116b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mContext.sendBroadcastAsUser(intent, user); 1117a5250c93928e256738125b265e10c96c3575597eMike Lockwood } 1118a5250c93928e256738125b265e10c96c3575597eMike Lockwood 11196a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private void sendUmsIntent(boolean c) { 11205ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn mContext.sendBroadcastAsUser( 11215ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn new Intent((c ? Intent.ACTION_UMS_CONNECTED : Intent.ACTION_UMS_DISCONNECTED)), 11225ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn UserHandle.ALL); 11236a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } 11246a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat 1125207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void validatePermission(String perm) { 11264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) { 11274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new SecurityException(String.format("Requires %s permission", perm)); 11284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 11297fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 11307fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 11312f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood // Storage list XML tags 11322f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood private static final String TAG_STORAGE_LIST = "StorageList"; 11332f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood private static final String TAG_STORAGE = "storage"; 11342f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 1135b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private void readStorageListLocked() { 1136b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mVolumes.clear(); 1137b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mVolumeStates.clear(); 1138b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 113913fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio Resources resources = mContext.getResources(); 114013fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio 11412f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood int id = com.android.internal.R.xml.storage_list; 11422f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood XmlResourceParser parser = resources.getXml(id); 11432f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood AttributeSet attrs = Xml.asAttributeSet(parser); 11442f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 11452f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood try { 11462f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood XmlUtils.beginDocument(parser, TAG_STORAGE_LIST); 11472f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood while (true) { 11482f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood XmlUtils.nextElement(parser); 11492f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 11502f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood String element = parser.getName(); 11512f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (element == null) break; 11522f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 11532f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (TAG_STORAGE.equals(element)) { 11542f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood TypedArray a = resources.obtainAttributes(attrs, 11552f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage); 11562f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 1157b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey String path = a.getString( 11582f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_mountPoint); 115913fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio int descriptionId = a.getResourceId( 116013fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio com.android.internal.R.styleable.Storage_storageDescription, -1); 11612f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood CharSequence description = a.getText( 11622f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_storageDescription); 11632f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood boolean primary = a.getBoolean( 11642f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_primary, false); 11652f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood boolean removable = a.getBoolean( 11662f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_removable, false); 11672f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood boolean emulated = a.getBoolean( 11682f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_emulated, false); 11692f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood int mtpReserve = a.getInt( 11702f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_mtpReserve, 0); 11718e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood boolean allowMassStorage = a.getBoolean( 11728e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood com.android.internal.R.styleable.Storage_allowMassStorage, false); 11737a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood // resource parser does not support longs, so XML value is in megabytes 11747a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood long maxFileSize = a.getInt( 11757a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood com.android.internal.R.styleable.Storage_maxFileSize, 0) * 1024L * 1024L; 11762f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 11772f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood Slog.d(TAG, "got storage path: " + path + " description: " + description + 11782f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood " primary: " + primary + " removable: " + removable + 11798e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood " emulated: " + emulated + " mtpReserve: " + mtpReserve + 11807a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood " allowMassStorage: " + allowMassStorage + 11817a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood " maxFileSize: " + maxFileSize); 1182b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1183b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (emulated) { 1184b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // For devices with emulated storage, we create separate 1185b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // volumes for each known user. 1186b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mEmulatedTemplate = new StorageVolume(null, descriptionId, true, false, 1187b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey true, mtpReserve, false, maxFileSize, null); 1188b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1189b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final UserManagerService userManager = UserManagerService.getInstance(); 1190920ace0bbc2d4133dbec991d2636c99a57d6245eAmith Yamasani for (UserInfo user : userManager.getUsers(false)) { 1191b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey createEmulatedVolumeForUserLocked(user.getUserHandle()); 11922f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 1193b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1194b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } else { 1195b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (path == null || description == null) { 1196b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Slog.e(TAG, "Missing storage path or description in readStorageList"); 11972f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } else { 1198b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume volume = new StorageVolume(new File(path), 1199b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey descriptionId, primary, removable, emulated, mtpReserve, 1200b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey allowMassStorage, maxFileSize, null); 1201b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey addVolumeLocked(volume); 12022f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 12032f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 1204b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 12052f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood a.recycle(); 12062f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 12072f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 12082f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } catch (XmlPullParserException e) { 12092f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood throw new RuntimeException(e); 12102f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } catch (IOException e) { 12112f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood throw new RuntimeException(e); 12122f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } finally { 1213b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // Compute storage ID for each physical volume; emulated storage is 1214b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // always 0 when defined. 1215b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey int index = isExternalStorageEmulated() ? 1 : 0; 1216b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey for (StorageVolume volume : mVolumes) { 1217b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (!volume.isEmulated()) { 1218b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey volume.setStorageId(index++); 1219b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1220fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood } 12212f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood parser.close(); 12222f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 12232f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 12242f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1226b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * Create and add new {@link StorageVolume} for given {@link UserHandle} 1227b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * using {@link #mEmulatedTemplate} as template. 1228b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey */ 1229b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private void createEmulatedVolumeForUserLocked(UserHandle user) { 1230b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (mEmulatedTemplate == null) { 1231b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey throw new IllegalStateException("Missing emulated volume multi-user template"); 1232b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1233b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1234b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final UserEnvironment userEnv = new UserEnvironment(user.getIdentifier()); 1235b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final File path = userEnv.getExternalStorageDirectory(); 1236b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume volume = StorageVolume.fromTemplate(mEmulatedTemplate, path, user); 1237b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey volume.setStorageId(0); 1238b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey addVolumeLocked(volume); 1239b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1240b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (mSystemReady) { 1241b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED); 1242b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } else { 1243b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // Place stub status for early callers to find 1244b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mVolumeStates.put(volume.getPath(), Environment.MEDIA_MOUNTED); 1245b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1246b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1247b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1248b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private void addVolumeLocked(StorageVolume volume) { 1249b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Slog.d(TAG, "addVolumeLocked() " + volume); 1250b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mVolumes.add(volume); 1251b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume existing = mVolumesByPath.put(volume.getPath(), volume); 1252b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (existing != null) { 1253b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey throw new IllegalStateException( 1254b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey "Volume at " + volume.getPath() + " already exists: " + existing); 1255b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1256b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1257b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1258b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private void removeVolumeLocked(StorageVolume volume) { 1259b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Slog.d(TAG, "removeVolumeLocked() " + volume); 1260b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mVolumes.remove(volume); 1261b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mVolumesByPath.remove(volume.getPath()); 1262b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mVolumeStates.remove(volume.getPath()); 1263b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1264b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1265b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private StorageVolume getPrimaryPhysicalVolume() { 1266b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 1267b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey for (StorageVolume volume : mVolumes) { 1268b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (volume.isPrimary() && !volume.isEmulated()) { 1269b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey return volume; 1270b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1271b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1272b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1273b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey return null; 1274b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1275b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1276b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey /** 1277207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Constructs a new MountService instance 1278207e538350665cea00e1aa70b8094beca4a34e45San Mehat * 1279207e538350665cea00e1aa70b8094beca4a34e45San Mehat * @param context Binder context for this service 1280207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 1281207e538350665cea00e1aa70b8094beca4a34e45San Mehat public MountService(Context context) { 1282207e538350665cea00e1aa70b8094beca4a34e45San Mehat mContext = context; 12832f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 1284b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 1285b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey readStorageListLocked(); 128603559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood } 128703559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood 1288207e538350665cea00e1aa70b8094beca4a34e45San Mehat // XXX: This will go away soon in favor of IMountServiceObserver 1289207e538350665cea00e1aa70b8094beca4a34e45San Mehat mPms = (PackageManagerService) ServiceManager.getService("package"); 1290207e538350665cea00e1aa70b8094beca4a34e45San Mehat 12915f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandlerThread = new HandlerThread("MountService"); 12925f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandlerThread.start(); 12935f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandler = new MountServiceHandler(mHandlerThread.getLooper()); 12945f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler 1295b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // Watch for user changes 1296b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final IntentFilter userFilter = new IntentFilter(); 1297b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey userFilter.addAction(Intent.ACTION_USER_ADDED); 1298b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey userFilter.addAction(Intent.ACTION_USER_REMOVED); 1299b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler); 1300b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1301b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // Watch for USB changes on primary volume 1302b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume primary = getPrimaryPhysicalVolume(); 1303b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (primary != null && primary.allowMassStorage()) { 1304b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mContext.registerReceiver( 1305b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_STATE), null, mHandler); 1306b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1307b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1308a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Add OBB Action Handler to MountService thread. 1309a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper()); 1310a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1311c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen /* 1312305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * Create the connection to vold with a maximum queue of twice the 1313305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * amount of containers we'd ever expect to have. This keeps an 1314305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * "asec list" from blocking a thread repeatedly. 1315305bcbf0c961840c4505770d084a1caacc074dbbKenny Root */ 1316470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25); 131751a573c76737733638c475f52e441c814e6645ccKenny Root 1318305bcbf0c961840c4505770d084a1caacc074dbbKenny Root Thread thread = new Thread(mConnector, VOLD_TAG); 1319207e538350665cea00e1aa70b8094beca4a34e45San Mehat thread.start(); 1320fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey 132107714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root // Add ourself to the Watchdog monitors if enabled. 132207714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root if (WATCHDOG_ENABLE) { 132307714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root Watchdog.getInstance().addMonitor(this); 132407714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root } 1325207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1326207e538350665cea00e1aa70b8094beca4a34e45San Mehat 1327b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey public void systemReady() { 1328b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mSystemReady = true; 1329b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget(); 1330b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1331b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1332207e538350665cea00e1aa70b8094beca4a34e45San Mehat /** 13334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Exposed API calls below here 13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13357fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 13364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void registerListener(IMountServiceListener listener) { 13374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 13384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = new MountServiceBinderListener(listener); 13394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 13404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat listener.asBinder().linkToDeath(bl, 0); 13414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.add(bl); 13424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 1343a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to link to listener death"); 13444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 13457fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void unregisterListener(IMountServiceListener listener) { 13494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 13504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for(MountServiceBinderListener bl : mListeners) { 13514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (bl.mListener == listener) { 13524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(mListeners.indexOf(bl)); 13535c25a2d338e9609d54e58cc1916c91cd8e9979abVairavan Srinivasan listener.asBinder().unlinkToDeath(bl, 0); 13544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return; 13554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 13564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13606ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu public void shutdown(final IMountShutdownObserver observer) { 13614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.SHUTDOWN); 13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1363a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Shutting down"); 1364b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 13657fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood for (String path : mVolumeStates.keySet()) { 13667fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String state = mVolumeStates.get(path); 13677fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 13687fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state.equals(Environment.MEDIA_SHARED)) { 13697fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood /* 13707fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * If the media is currently shared, unshare it. 13717fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * XXX: This is still dangerous!. We should not 13727fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * be rebooting at *all* if UMS is enabled, since 13737fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * the UMS host could have dirty FAT cache entries 13747fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * yet to flush. 13757fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood */ 13767fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood setUsbMassStorageEnabled(false); 13777fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } else if (state.equals(Environment.MEDIA_CHECKING)) { 13787fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood /* 13797fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * If the media is being checked, then we need to wait for 13807fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * it to complete before being able to proceed. 13817fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood */ 13827fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood // XXX: @hackbod - Should we disable the ANR timer here? 13837fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood int retries = 30; 13847fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) { 13857fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood try { 13867fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Thread.sleep(1000); 13877fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } catch (InterruptedException iex) { 13887fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.e(TAG, "Interrupted while waiting for media", iex); 13897fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood break; 13907fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 13917fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood state = Environment.getExternalStorageState(); 13927fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 13937fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (retries == 0) { 13947fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.e(TAG, "Timed out waiting for media to check"); 13957fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 13964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 13977fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 13987fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state.equals(Environment.MEDIA_MOUNTED)) { 13997fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood // Post a unmount message. 14007fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood ShutdownCallBack ucb = new ShutdownCallBack(path, observer); 14017fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb)); 14027fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } else if (observer != null) { 14037fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood /* 14047fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * Observer is waiting for onShutDownComplete when we are done. 14057fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * Since nothing will be done send notification directly so shutdown 14067fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * sequence can continue. 14077fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood */ 14087fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood try { 14097fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood observer.onShutDownComplete(StorageResultCode.OperationSucceeded); 14107fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } catch (RemoteException e) { 14117fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.w(TAG, "RemoteException when shutting down"); 14127fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 14137fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 14145d0db4d356346bee68aec9a124df70dbaa9aaed1Johan Alfven } 14151f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 14169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14180eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private boolean getUmsEnabling() { 14190eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu synchronized (mListeners) { 14200eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu return mUmsEnabling; 14210eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 14220eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 14230eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 14240eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private void setUmsEnabling(boolean enable) { 14250eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu synchronized (mListeners) { 1426fc71125104650c61ab5b04f4c943de761d58cba6Tony Wu mUmsEnabling = enable; 14270eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 14280eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 14290eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 1430b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageConnected() { 1431207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 14327fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 14330eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (getUmsEnabling()) { 1434b104340496e3a531e26c8f428c808eca0e039f50San Mehat return true; 1435b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1436ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood synchronized (mListeners) { 1437ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood return mUmsAvailable; 1438ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood } 14394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14410eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu public void setUsbMassStorageEnabled(boolean enable) { 1442207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 14430eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 14440eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 1445b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume primary = getPrimaryPhysicalVolume(); 1446b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (primary == null) return; 1447b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 14480eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // TODO: Add support for multiple share methods 1449b104340496e3a531e26c8f428c808eca0e039f50San Mehat 14500eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 14510eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * If the volume is mounted and we're enabling then unmount it 14520eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 1453b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey String path = primary.getPath(); 14540eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String vs = getVolumeState(path); 14550eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String method = "ums"; 14560eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (enable && vs.equals(Environment.MEDIA_MOUNTED)) { 14570eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Override for isUsbMassStorageEnabled() 14580eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu setUmsEnabling(enable); 14590eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true); 14600eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb)); 14610eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Clear override 14620eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu setUmsEnabling(false); 14630eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 14640eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 14650eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * If we disabled UMS then mount the volume 14660eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 14670eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (!enable) { 14680eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doShareUnshareVolume(path, method, enable); 14690eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (doMountVolume(path) != StorageResultCode.OperationSucceeded) { 1470a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to remount " + path + 14710eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu " after disabling share method " + method); 14720eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 14730eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * Even though the mount failed, the unshare didn't so don't indicate an error. 14740eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * The mountVolume() call will have set the storage state and sent the necessary 14750eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * broadcasts. 14760eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 14770eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 14780eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 14794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1481b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageEnabled() { 1482207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1483b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1484b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume primary = getPrimaryPhysicalVolume(); 1485b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (primary != null) { 1486b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey return doGetVolumeShared(primary.getPath(), "ums"); 1487b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } else { 1488b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey return false; 1489b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14919ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * @return state of the volume at the specified mount point 14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String getVolumeState(String mountPoint) { 1496b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 14977fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String state = mVolumeStates.get(mountPoint); 14987fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state == null) { 14997fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume"); 150018db5c5690472f9da6ce2d580067307378675809Ken Sumrall if (SystemProperties.get("vold.encrypt_progress").length() != 0) { 150118db5c5690472f9da6ce2d580067307378675809Ken Sumrall state = Environment.MEDIA_REMOVED; 150218db5c5690472f9da6ce2d580067307378675809Ken Sumrall } else { 150318db5c5690472f9da6ce2d580067307378675809Ken Sumrall throw new IllegalArgumentException(); 150418db5c5690472f9da6ce2d580067307378675809Ken Sumrall } 15057fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 15064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 15077fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood return state; 15087fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1511b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey @Override 1512e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root public boolean isExternalStorageEmulated() { 1513b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey return mEmulatedTemplate != null; 1514e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root } 1515e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root 15164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int mountVolume(String path) { 15174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1519207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1520207e538350665cea00e1aa70b8094beca4a34e45San Mehat return doMountVolume(path); 15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 152313c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo public void unmountVolume(String path, boolean force, boolean removeEncryption) { 15244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1525207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15278a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu String volState = getVolumeState(path); 152813c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo if (DEBUG_UNMOUNT) { 152913c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo Slog.i(TAG, "Unmounting " + path 153013c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo + " force = " + force 153113c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo + " removeEncryption = " + removeEncryption); 153213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo } 15338a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (Environment.MEDIA_UNMOUNTED.equals(volState) || 15348a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_REMOVED.equals(volState) || 15358a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_SHARED.equals(volState) || 15368a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_UNMOUNTABLE.equals(volState)) { 15378a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // Media already unmounted or cannot be unmounted. 15388a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // TODO return valid return code when adding observer call back. 15398a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu return; 15408a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 154113c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo UnmountCallBack ucb = new UnmountCallBack(path, force, removeEncryption); 1542c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb)); 15434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int formatVolume(String path) { 15464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); 1547207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 15489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1549207e538350665cea00e1aa70b8094beca4a34e45San Mehat return doFormatVolume(path); 15509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15513697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1552ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood public int[] getStorageUsers(String path) { 1553c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1554c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat waitForReady(); 1555c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat try { 1556dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final String[] r = NativeDaemonEvent.filterMessageList( 1557dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.executeForList("storage", "users", path), 1558dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey VoldResponseCode.StorageUsersListResult); 1559dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey 1560c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat // FMT: <pid> <process name> 1561c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat int[] data = new int[r.length]; 1562c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat for (int i = 0; i < r.length; i++) { 1563dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey String[] tok = r[i].split(" "); 1564c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat try { 1565c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat data[i] = Integer.parseInt(tok[0]); 1566c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } catch (NumberFormatException nfe) { 1567a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Error parsing pid %s", tok[0])); 1568c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return new int[0]; 1569c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1570c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1571c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return data; 1572c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } catch (NativeDaemonConnectorException e) { 1573a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to retrieve storage users list", e); 1574c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return new int[0]; 1575c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1576c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1577c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat 1578b104340496e3a531e26c8f428c808eca0e039f50San Mehat private void warnOnNotMounted() { 1579b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume primary = getPrimaryPhysicalVolume(); 158032ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey if (primary != null) { 158132ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey boolean mounted = false; 158232ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey try { 158332ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey mounted = Environment.MEDIA_MOUNTED.equals(getVolumeState(primary.getPath())); 158432ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey } catch (IllegalStateException e) { 158532ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey } 158632ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey 158732ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey if (!mounted) { 158832ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey Slog.w(TAG, "getSecureContainerList() called when storage not mounted"); 158932ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey } 1590b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1591b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1592b104340496e3a531e26c8f428c808eca0e039f50San Mehat 15934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String[] getSecureContainerList() { 15944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 1595207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1596b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1597f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 15984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1599dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return NativeDaemonEvent.filterMessageList( 1600dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult); 16014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 16024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return new String[0]; 160302735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 16043697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 16053697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 16066dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root public int createSecureContainer(String id, int sizeMb, String fstype, String key, 16076dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root int ownerUid, boolean external) { 16084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_CREATE); 1609207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1610b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 16114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1612b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 16134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 16146dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root mConnector.execute("asec", "create", id, sizeMb, fstype, key, ownerUid, 16156dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root external ? "1" : "0"); 16164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1617b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 161802735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1619a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1620a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (rc == StorageResultCode.OperationSucceeded) { 1621a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1622a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat mAsecMountSet.add(id); 1623a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1624a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 16254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 16263697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 16273697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 16284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int finalizeSecureContainer(String id) { 16294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_CREATE); 1630b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 16314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1632b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 16334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1634dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("asec", "finalize", id); 1635a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat /* 1636a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat * Finalization does a remount, so no need 1637a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat * to update mAsecMountSet 1638a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat */ 16396dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root } catch (NativeDaemonConnectorException e) { 16406dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root rc = StorageResultCode.OperationFailedInternalError; 16416dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root } 16426dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root return rc; 16436dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root } 16446dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root 16456dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root public int fixPermissionsSecureContainer(String id, int gid, String filename) { 16466dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root validatePermission(android.Manifest.permission.ASEC_CREATE); 16476dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root warnOnNotMounted(); 16486dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root 16496dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root int rc = StorageResultCode.OperationSucceeded; 16506dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root try { 16516dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root mConnector.execute("asec", "fixperms", id, gid, filename); 16526dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root /* 16536dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root * Fix permissions does a remount, so no need to update 16546dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root * mAsecMountSet 16556dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root */ 16564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1657b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 165802735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 16594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 16603697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 16613697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1662d970998b0d489774ad1c5b94b47d233912f00214San Mehat public int destroySecureContainer(String id, boolean force) { 16634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_DESTROY); 1664207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1665b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1666f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 1667aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 1668aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 1669aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 1670aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 1671aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 1672aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 1673aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 1674aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 1675b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 16764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1677dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final Command cmd = new Command("asec", "destroy", id); 1678dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey if (force) { 1679dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey cmd.appendArg("force"); 1680dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } 1681dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute(cmd); 16824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1683d970998b0d489774ad1c5b94b47d233912f00214San Mehat int code = e.getCode(); 1684d970998b0d489774ad1c5b94b47d233912f00214San Mehat if (code == VoldResponseCode.OpFailedStorageBusy) { 1685d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedStorageBusy; 1686d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else { 1687d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedInternalError; 1688d970998b0d489774ad1c5b94b47d233912f00214San Mehat } 168902735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1690a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1691a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (rc == StorageResultCode.OperationSucceeded) { 1692a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1693a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (mAsecMountSet.contains(id)) { 1694a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat mAsecMountSet.remove(id); 1695a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1696a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1697a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1698a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 16994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 17003697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 17019ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 17024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int mountSecureContainer(String id, String key, int ownerUid) { 17034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 1704207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1705b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 17064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1707a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1708a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (mAsecMountSet.contains(id)) { 1709a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageMounted; 1710a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1711a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1712a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1713b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 17144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1715dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("asec", "mount", id, key, ownerUid); 17164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1717f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root int code = e.getCode(); 1718f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root if (code != VoldResponseCode.OpFailedStorageBusy) { 1719f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root rc = StorageResultCode.OperationFailedInternalError; 1720f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root } 172102735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 17226cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 17236cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (rc == StorageResultCode.OperationSucceeded) { 17246cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 17256cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat mAsecMountSet.add(id); 17266cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 17276cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 17284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 17293697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 17303697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1731d970998b0d489774ad1c5b94b47d233912f00214San Mehat public int unmountSecureContainer(String id, boolean force) { 17324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 1733207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1734b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 17354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 17366cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 17376cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (!mAsecMountSet.contains(id)) { 1738a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageNotMounted; 17396cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 17406cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 17416cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 1742aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 1743aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 1744aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 1745aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 1746aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 1747aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 1748aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 1749aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 1750b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 17514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1752dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final Command cmd = new Command("asec", "unmount", id); 1753dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey if (force) { 1754dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey cmd.appendArg("force"); 1755dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } 1756dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute(cmd); 17574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1758d970998b0d489774ad1c5b94b47d233912f00214San Mehat int code = e.getCode(); 1759d970998b0d489774ad1c5b94b47d233912f00214San Mehat if (code == VoldResponseCode.OpFailedStorageBusy) { 1760d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedStorageBusy; 1761d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else { 1762d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedInternalError; 1763d970998b0d489774ad1c5b94b47d233912f00214San Mehat } 176402735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 17656cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 17666cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (rc == StorageResultCode.OperationSucceeded) { 17676cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 17686cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat mAsecMountSet.remove(id); 17696cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 17706cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 17714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 17729dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat } 17739dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat 17746cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat public boolean isSecureContainerMounted(String id) { 17756cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 17766cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat waitForReady(); 17776cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat warnOnNotMounted(); 17786cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 17796cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 17806cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat return mAsecMountSet.contains(id); 17816cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 17826cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 17836cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 17844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int renameSecureContainer(String oldId, String newId) { 17854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_RENAME); 1786207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1787b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 17884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1789a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 179085451ee15fdf6cae371dc3005441988c7d426401San Mehat /* 17919ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks * Because a mounted container has active internal state which cannot be 179285451ee15fdf6cae371dc3005441988c7d426401San Mehat * changed while active, we must ensure both ids are not currently mounted. 179385451ee15fdf6cae371dc3005441988c7d426401San Mehat */ 179485451ee15fdf6cae371dc3005441988c7d426401San Mehat if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) { 1795a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageMounted; 1796a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1797a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1798a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1799b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 18004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1801dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("asec", "rename", oldId, newId); 18024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1803b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 180402735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1805a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 18064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 180745f61040823d8c442838f75cde8760f236603daeSan Mehat } 180845f61040823d8c442838f75cde8760f236603daeSan Mehat 18094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String getSecureContainerPath(String id) { 18104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 1811207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1812b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1813f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 1814dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 18152d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat try { 1816dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("asec", "path", id); 1817dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event.checkCode(VoldResponseCode.AsecPathResult); 1818dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return event.getMessage(); 18192d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat } catch (NativeDaemonConnectorException e) { 18202d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat int code = e.getCode(); 18212d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat if (code == VoldResponseCode.OpFailedStorageNotFound) { 1822a20c8ef471666cf8b0dca91a8739ff18af1741a5Fredrik Helmer Slog.i(TAG, String.format("Container '%s' not found", id)); 1823a20c8ef471666cf8b0dca91a8739ff18af1741a5Fredrik Helmer return null; 182422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else { 18252d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat throw new IllegalStateException(String.format("Unexpected response code %d", code)); 182622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 182722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 182822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 1829292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn 1830292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn public String getSecureContainerFilesystemPath(String id) { 1831292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn validatePermission(android.Manifest.permission.ASEC_ACCESS); 1832292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn waitForReady(); 1833292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn warnOnNotMounted(); 1834292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn 1835dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 1836292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn try { 1837dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("asec", "fspath", id); 1838dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event.checkCode(VoldResponseCode.AsecPathResult); 1839dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return event.getMessage(); 1840292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn } catch (NativeDaemonConnectorException e) { 1841292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn int code = e.getCode(); 1842292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn if (code == VoldResponseCode.OpFailedStorageNotFound) { 1843292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn Slog.i(TAG, String.format("Container '%s' not found", id)); 1844292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn return null; 1845292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn } else { 1846292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn throw new IllegalStateException(String.format("Unexpected response code %d", code)); 1847292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn } 1848292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn } 1849292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn } 1850e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu 1851e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu public void finishMediaUpdate() { 1852e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE); 1853e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu } 185402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1855a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) { 1856a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (callerUid == android.os.Process.SYSTEM_UID) { 1857a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return true; 1858a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1859a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 186002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (packageName == null) { 186102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return false; 186202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 186302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1864f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn final int packageUid = mPms.getPackageUid(packageName, UserHandle.getUserId(callerUid)); 186502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 186602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (DEBUG_OBB) { 186702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root Slog.d(TAG, "packageName = " + packageName + ", packageUid = " + 186802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root packageUid + ", callerUid = " + callerUid); 186902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 187002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 187102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return callerUid == packageUid; 187202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 187302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 18744fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey public String getMountedObbPath(String rawPath) { 18754fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 1876af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 187702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root waitForReady(); 187802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root warnOnNotMounted(); 187902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 18804fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final ObbState state; 18814fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey synchronized (mObbPathToStateMap) { 18824fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey state = mObbPathToStateMap.get(rawPath); 18834fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 18844fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (state == null) { 18854fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Slog.w(TAG, "Failed to find OBB mounted at " + rawPath); 18864fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return null; 18874fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 18884fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 1889dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 189002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root try { 18914fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey event = mConnector.execute("obb", "path", state.voldPath); 1892dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event.checkCode(VoldResponseCode.AsecPathResult); 1893dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return event.getMessage(); 189402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } catch (NativeDaemonConnectorException e) { 189502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root int code = e.getCode(); 189602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (code == VoldResponseCode.OpFailedStorageNotFound) { 1897a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return null; 189802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } else { 189902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root throw new IllegalStateException(String.format("Unexpected response code %d", code)); 190002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 190102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 190202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 190302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 19044fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey @Override 19054fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey public boolean isObbMounted(String rawPath) { 19064fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 1907a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root synchronized (mObbMounts) { 19084fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return mObbPathToStateMap.containsKey(rawPath); 1909a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1910a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1911a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 19124fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey @Override 19134fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey public void mountObb( 19144fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) { 19154fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 19164fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null"); 19174fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(token, "token cannot be null"); 19184fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 19194fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final int callingUid = Binder.getCallingUid(); 19204fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce); 19214fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final ObbAction action = new MountObbAction(obbState, key, callingUid); 1922a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 1923a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1924a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1925a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Send to OBB handler: " + action.toString()); 192602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 192702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 19284fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey @Override 19294fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) { 19304fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 19314fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 19324fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final ObbState existingState; 19334fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey synchronized (mObbPathToStateMap) { 19344fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey existingState = mObbPathToStateMap.get(rawPath); 1935f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root } 1936f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root 19374fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (existingState != null) { 19384fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey // TODO: separate state object from request data 19394fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final int callingUid = Binder.getCallingUid(); 19404fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final ObbState newState = new ObbState( 19414fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey rawPath, existingState.canonicalPath, callingUid, token, nonce); 19424fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final ObbAction action = new UnmountObbAction(newState, force); 19434fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 1944a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 19454fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (DEBUG_OBB) 19464fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Slog.i(TAG, "Send to OBB handler: " + action.toString()); 19474fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } else { 19484fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Slog.w(TAG, "Unknown OBB mount at " + rawPath); 19494fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 1950a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 195102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1952444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo @Override 1953444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo public int getEncryptionState() { 1954444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 1955444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo "no permission to access the crypt keeper"); 1956444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo 1957444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo waitForReady(); 1958444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo 1959dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 1960444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo try { 1961dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("cryptfs", "cryptocomplete"); 1962dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return Integer.parseInt(event.getMessage()); 1963444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo } catch (NumberFormatException e) { 1964444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo // Bad result - unexpected. 1965444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete"); 1966444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo return ENCRYPTION_STATE_ERROR_UNKNOWN; 1967444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo } catch (NativeDaemonConnectorException e) { 1968444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo // Something bad happened. 1969444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo Slog.w(TAG, "Error in communicating with cryptfs in validating"); 1970444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo return ENCRYPTION_STATE_ERROR_UNKNOWN; 1971444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo } 1972444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo } 1973444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo 1974444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo @Override 19755af0b916f850486cff4797355bf9e7dc3352fe00Jason parks public int decryptStorage(String password) { 1976f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (TextUtils.isEmpty(password)) { 1977f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks throw new IllegalArgumentException("password cannot be empty"); 19785af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 19795af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 19808888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 19818888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks "no permission to access the crypt keeper"); 19825af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 19835af0b916f850486cff4797355bf9e7dc3352fe00Jason parks waitForReady(); 19845af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 19855af0b916f850486cff4797355bf9e7dc3352fe00Jason parks if (DEBUG_EVENTS) { 19865af0b916f850486cff4797355bf9e7dc3352fe00Jason parks Slog.i(TAG, "decrypting storage..."); 19875af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 19885af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 1989dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 19905af0b916f850486cff4797355bf9e7dc3352fe00Jason parks try { 1991dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("cryptfs", "checkpw", password); 19929ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 1993da6aedf716bfdd40148823fb63d666d34b7b425eFredrik Roubert final int code = Integer.parseInt(event.getMessage()); 19949ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks if (code == 0) { 19959ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks // Decrypt was successful. Post a delayed message before restarting in order 19969ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks // to let the UI to clear itself 19979ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks mHandler.postDelayed(new Runnable() { 19989ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks public void run() { 199931c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey try { 2000dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("cryptfs", "restart"); 200131c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey } catch (NativeDaemonConnectorException e) { 200231c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey Slog.e(TAG, "problem executing in background", e); 200331c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey } 20049ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks } 2005f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks }, 1000); // 1 second 20069ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks } 20079ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 20089ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks return code; 20095af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } catch (NativeDaemonConnectorException e) { 20105af0b916f850486cff4797355bf9e7dc3352fe00Jason parks // Decryption failed 20115af0b916f850486cff4797355bf9e7dc3352fe00Jason parks return e.getCode(); 20125af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 20135af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 20145af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 201556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks public int encryptStorage(String password) { 2016f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (TextUtils.isEmpty(password)) { 2017f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks throw new IllegalArgumentException("password cannot be empty"); 201856aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 201956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 20208888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 20218888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks "no permission to access the crypt keeper"); 202256aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 202356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks waitForReady(); 202456aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 202556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks if (DEBUG_EVENTS) { 20268888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks Slog.i(TAG, "encrypting storage..."); 202756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 202856aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 202956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks try { 2030dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("cryptfs", "enablecrypto", "inplace", password); 203156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } catch (NativeDaemonConnectorException e) { 203256aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks // Encryption failed 203356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks return e.getCode(); 203456aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 203556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 203656aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks return 0; 203756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 203856aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 2039f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks public int changeEncryptionPassword(String password) { 2040f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (TextUtils.isEmpty(password)) { 2041f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks throw new IllegalArgumentException("password cannot be empty"); 2042f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 2043f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 2044f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 2045f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks "no permission to access the crypt keeper"); 2046f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 2047f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks waitForReady(); 2048f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 2049f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (DEBUG_EVENTS) { 2050f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks Slog.i(TAG, "changing encryption password..."); 2051f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 2052f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 2053dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 2054f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks try { 2055dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("cryptfs", "changepw", password); 2056dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return Integer.parseInt(event.getMessage()); 2057f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } catch (NativeDaemonConnectorException e) { 2058f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks // Encryption failed 2059f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks return e.getCode(); 2060f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 2061f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 2062f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 206332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate /** 206432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate * Validate a user-supplied password string with cryptfs 206532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate */ 206632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate @Override 206732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate public int verifyEncryptionPassword(String password) throws RemoteException { 206832418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate // Only the system process is permitted to validate passwords 206932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { 207032418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate throw new SecurityException("no permission to access the crypt keeper"); 207132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } 207232418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 207332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 207432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate "no permission to access the crypt keeper"); 207532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 207632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate if (TextUtils.isEmpty(password)) { 207732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate throw new IllegalArgumentException("password cannot be empty"); 207832418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } 207932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 208032418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate waitForReady(); 208132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 208232418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate if (DEBUG_EVENTS) { 208332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate Slog.i(TAG, "validating encryption password..."); 208432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } 208532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 2086dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 208732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate try { 2088dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("cryptfs", "verifypw", password); 2089dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey Slog.i(TAG, "cryptfs verifypw => " + event.getMessage()); 2090dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return Integer.parseInt(event.getMessage()); 209132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } catch (NativeDaemonConnectorException e) { 209232418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate // Encryption failed 209332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate return e.getCode(); 209432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } 209532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } 209632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 2097b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey @Override 2098b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey public StorageVolume[] getVolumeList() { 2099b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final int callingUserId = UserHandle.getCallingUserId(); 2100b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final boolean accessAll = (mContext.checkPermission( 2101b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey android.Manifest.permission.ACCESS_ALL_EXTERNAL_STORAGE, 2102b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Binder.getCallingPid(), Binder.getCallingUid()) == PERMISSION_GRANTED); 2103b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 2104b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 2105b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final ArrayList<StorageVolume> filtered = Lists.newArrayList(); 2106b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey for (StorageVolume volume : mVolumes) { 2107b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final UserHandle owner = volume.getOwner(); 2108b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final boolean ownerMatch = owner == null || owner.getIdentifier() == callingUserId; 2109b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (accessAll || ownerMatch) { 2110b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey filtered.add(volume); 2111b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 21128fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood } 2113b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey return filtered.toArray(new StorageVolume[filtered.size()]); 21148fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood } 21158fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood } 21168fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood 2117af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private void addObbStateLocked(ObbState obbState) throws RemoteException { 2118af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IBinder binder = obbState.getBinder(); 2119af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root List<ObbState> obbStates = mObbMounts.get(binder); 21205919ac6b4188285324646772501ef4b97b353cf4Kenny Root 2121af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates == null) { 2122af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates = new ArrayList<ObbState>(); 2123af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.put(binder, obbStates); 2124af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 2125af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root for (final ObbState o : obbStates) { 21264fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (o.rawPath.equals(obbState.rawPath)) { 2127af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalStateException("Attempt to add ObbState twice. " 2128af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + "This indicates an error in the MountService logic."); 21295919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 21305919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 213102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 213202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2133af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates.add(obbState); 2134af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 2135af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState.link(); 2136af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (RemoteException e) { 2137af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root /* 2138af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * The binder died before we could link it, so clean up our state 2139af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * and return failure. 2140af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root */ 2141af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates.remove(obbState); 2142af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.isEmpty()) { 2143af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.remove(binder); 214405105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 21455919ac6b4188285324646772501ef4b97b353cf4Kenny Root 2146af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Rethrow the error so mountObb can get it 2147af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw e; 214802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 2149af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 21504fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey mObbPathToStateMap.put(obbState.rawPath, obbState); 2151a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 215202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2153af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private void removeObbStateLocked(ObbState obbState) { 2154af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IBinder binder = obbState.getBinder(); 2155af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStates = mObbMounts.get(binder); 2156af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates != null) { 2157af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.remove(obbState)) { 2158af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState.unlink(); 2159af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2160af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.isEmpty()) { 2161af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.remove(binder); 2162af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 216338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2164af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 21654fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey mObbPathToStateMap.remove(obbState.rawPath); 216638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 216738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2168a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private class ObbActionHandler extends Handler { 2169a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean mBound = false; 2170480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root private final List<ObbAction> mActions = new LinkedList<ObbAction>(); 2171a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2172a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbActionHandler(Looper l) { 2173a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(l); 2174a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2175a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2176a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 2177a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleMessage(Message msg) { 2178a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root switch (msg.what) { 2179a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_RUN_ACTION: { 2180480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root final ObbAction action = (ObbAction) msg.obj; 2181a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2182a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2183a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString()); 2184a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2185a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // If a bind was already initiated we don't really 2186a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // need to do anything. The pending install 2187a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // will be processed later on. 2188a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!mBound) { 2189a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // If this is the only one pending we might 2190a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // have to bind to the service again. 2191a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!connectToService()) { 2192a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Failed to bind to media container service"); 2193a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 2194a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return; 2195a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2196a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2197735de3b38abbd6564082a819377673ee593744a6Kenny Root 2198735de3b38abbd6564082a819377673ee593744a6Kenny Root mActions.add(action); 2199a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 2200a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2201a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_BOUND: { 2202a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2203a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_BOUND"); 2204a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (msg.obj != null) { 2205a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContainerService = (IMediaContainerService) msg.obj; 2206a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2207a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mContainerService == null) { 2208a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Something seriously wrong. Bail out 2209a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Cannot bind to media container service"); 2210a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root for (ObbAction action : mActions) { 2211a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Indicate service bind error 2212a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 2213a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2214a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.clear(); 2215a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else if (mActions.size() > 0) { 2216480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root final ObbAction action = mActions.get(0); 2217a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (action != null) { 2218a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.execute(this); 2219a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2220a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 2221a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Should never happen ideally. 2222a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.w(TAG, "Empty queue"); 2223a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2224a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 2225a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2226a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_RECONNECT: { 2227a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2228a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_RECONNECT"); 2229a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() > 0) { 2230a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mBound) { 2231a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root disconnectService(); 2232a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2233a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!connectToService()) { 2234a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Failed to bind to media container service"); 2235a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root for (ObbAction action : mActions) { 2236a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Indicate service bind error 2237a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 2238a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2239a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.clear(); 2240a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2241a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2242a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 2243a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2244a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_UNBIND: { 2245a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2246a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_UNBIND"); 2247a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2248a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Delete pending install 2249a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() > 0) { 2250a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.remove(0); 2251a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2252a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() == 0) { 2253a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mBound) { 2254a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root disconnectService(); 2255a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2256a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 2257a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // There are more pending requests in queue. 2258a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Just post MCS_BOUND message to trigger processing 2259a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // of next pending install. 2260a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND); 2261a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2262a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 2263a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2264af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root case OBB_FLUSH_MOUNT_STATE: { 2265af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final String path = (String) msg.obj; 2266af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2267af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 2268af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.i(TAG, "Flushing all OBB state for path " + path); 2269af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2270af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 2271af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>(); 2272af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 22734fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final Iterator<ObbState> i = mObbPathToStateMap.values().iterator(); 2274af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (i.hasNext()) { 22754fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final ObbState state = i.next(); 2276af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2277af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root /* 2278af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * If this entry's source file is in the volume path 2279af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * that got unmounted, remove it because it's no 2280af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * longer valid. 2281af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root */ 22824fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (state.canonicalPath.startsWith(path)) { 22834fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey obbStatesToRemove.add(state); 2284af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2285af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2286af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2287af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root for (final ObbState obbState : obbStatesToRemove) { 2288af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 22894fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Slog.i(TAG, "Removing state for " + obbState.rawPath); 2290af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2291af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root removeObbStateLocked(obbState); 2292af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2293af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 22944fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey obbState.token.onObbResult(obbState.rawPath, obbState.nonce, 2295af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root OnObbStateChangeListener.UNMOUNTED); 2296af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (RemoteException e) { 2297af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.i(TAG, "Couldn't send unmount notification for OBB: " 22984fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey + obbState.rawPath); 2299af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2300af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2301af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2302af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root break; 2303af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 230402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 230502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 230602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2307a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean connectToService() { 2308a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2309a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Trying to bind to DefaultContainerService"); 2310a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2311a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); 2312a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) { 2313a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mBound = true; 2314a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return true; 231502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 2316a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return false; 2317a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2318a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2319a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private void disconnectService() { 2320a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContainerService = null; 2321a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mBound = false; 2322a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContext.unbindService(mDefContainerConn); 232302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 232402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 232502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2326a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root abstract class ObbAction { 2327a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int MAX_RETRIES = 3; 2328a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private int mRetries; 232902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2330a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbState mObbState; 2331a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2332a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbAction(ObbState obbState) { 2333a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbState = obbState; 233402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 233502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2336a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void execute(ObbActionHandler handler) { 2337a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root try { 2338a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2339444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo Slog.i(TAG, "Starting to execute action: " + toString()); 2340a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mRetries++; 2341a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mRetries > MAX_RETRIES) { 2342a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); 2343480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 2344a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleError(); 2345a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return; 2346a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 2347a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleExecute(); 2348a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2349a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Posting install MCS_UNBIND"); 2350a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 2351a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2352a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } catch (RemoteException e) { 2353a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2354a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Posting install MCS_RECONNECT"); 2355a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT); 2356a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } catch (Exception e) { 2357a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2358a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.d(TAG, "Error handling OBB action", e); 2359a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleError(); 236017eb6fb07cc6965f09c51adc70b3c291f57a784aKenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 236102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 2362a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 236302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 236405105f7abe02b2dff91d6260b3628c8b97816babKenny Root abstract void handleExecute() throws RemoteException, IOException; 2365a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root abstract void handleError(); 236638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 236738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root protected ObbInfo getObbInfo() throws IOException { 236838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root ObbInfo obbInfo; 236938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root try { 23704fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey obbInfo = mContainerService.getObbInfo(mObbState.ownerPath); 237138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } catch (RemoteException e) { 237238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for " 23734fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey + mObbState.ownerPath); 237438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root obbInfo = null; 237538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 237638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root if (obbInfo == null) { 23774fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey throw new IOException("Couldn't read OBB file: " + mObbState.ownerPath); 237838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 237938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return obbInfo; 238038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 238138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2382af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root protected void sendNewStatusOrIgnore(int status) { 2383af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (mObbState == null || mObbState.token == null) { 2384af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2385af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2386af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 238738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root try { 23884fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status); 238938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } catch (RemoteException e) { 239038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged"); 239138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 239238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2393a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2394a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2395a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class MountObbAction extends ObbAction { 2396444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo private final String mKey; 23974fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey private final int mCallingUid; 2398a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 23994fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey MountObbAction(ObbState obbState, String key, int callingUid) { 2400a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(obbState); 2401a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mKey = key; 24024fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey mCallingUid = callingUid; 2403a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2404a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 24055af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 2406735de3b38abbd6564082a819377673ee593744a6Kenny Root public void handleExecute() throws IOException, RemoteException { 2407af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root waitForReady(); 2408af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root warnOnNotMounted(); 2409af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 241038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root final ObbInfo obbInfo = getObbInfo(); 241138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 24124fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) { 2413af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename 2414af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + " which is owned by " + obbInfo.packageName); 2415af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); 2416af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2417af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2418af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2419af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final boolean isMounted; 2420af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 24214fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath); 2422af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2423af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (isMounted) { 2424af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename); 2425af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED); 2426af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2427af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2428af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2429af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final String hashedKey; 2430af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (mKey == null) { 2431af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root hashedKey = "none"; 2432af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 2433af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 24343b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 24353b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 24363b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt, 24373b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE); 24383b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root SecretKey key = factory.generateSecret(ks); 24393b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root BigInteger bi = new BigInteger(key.getEncoded()); 24403b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root hashedKey = bi.toString(16); 2441af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NoSuchAlgorithmException e) { 24423b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root Slog.e(TAG, "Could not load PBKDF2 algorithm", e); 24433b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 24443b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root return; 24453b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root } catch (InvalidKeySpecException e) { 24463b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e); 24473b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 2448af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 244938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2450a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2451a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2452af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int rc = StorageResultCode.OperationSucceeded; 2453af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 2454dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute( 24554fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey "obb", "mount", mObbState.voldPath, hashedKey, mObbState.ownerGid); 2456af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NativeDaemonConnectorException e) { 2457af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int code = e.getCode(); 2458af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (code != VoldResponseCode.OpFailedStorageBusy) { 2459af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedInternalError; 2460a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2461af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2462a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2463af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (rc == StorageResultCode.OperationSucceeded) { 2464af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 24654fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Slog.d(TAG, "Successfully mounted OBB " + mObbState.voldPath); 246638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2467af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 2468af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root addObbStateLocked(mObbState); 2469a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 247038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2471af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED); 247202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } else { 247305105f7abe02b2dff91d6260b3628c8b97816babKenny Root Slog.e(TAG, "Couldn't mount OBB file: " + rc); 2474a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2475af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT); 247602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 247702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 247802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 24795af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 2480a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleError() { 2481af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 248202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 2483a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2484a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 2485a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public String toString() { 2486a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root StringBuilder sb = new StringBuilder(); 2487a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("MountObbAction{"); 24884fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append(mObbState); 2489a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append('}'); 2490a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return sb.toString(); 2491a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2492a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2493a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2494a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class UnmountObbAction extends ObbAction { 2495444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo private final boolean mForceUnmount; 2496a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2497a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root UnmountObbAction(ObbState obbState, boolean force) { 2498a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(obbState); 2499a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mForceUnmount = force; 2500a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2501a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 25025af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 250338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root public void handleExecute() throws IOException { 2504af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root waitForReady(); 2505af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root warnOnNotMounted(); 2506af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 250738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root final ObbInfo obbInfo = getObbInfo(); 2508a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 25094fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final ObbState existingState; 251038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root synchronized (mObbMounts) { 25114fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey existingState = mObbPathToStateMap.get(mObbState.rawPath); 2512af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 251338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 25144fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (existingState == null) { 2515af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED); 2516af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2517a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2518a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 25194fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (existingState.ownerGid != mObbState.ownerGid) { 25204fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath 25214fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey + " (owned by GID " + existingState.ownerGid + ")"); 2522af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); 2523af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2524af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2525a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2526af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int rc = StorageResultCode.OperationSucceeded; 2527af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 25284fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final Command cmd = new Command("obb", "unmount", mObbState.voldPath); 2529dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey if (mForceUnmount) { 2530dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey cmd.appendArg("force"); 2531dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } 2532dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute(cmd); 2533af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NativeDaemonConnectorException e) { 2534af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int code = e.getCode(); 2535af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (code == VoldResponseCode.OpFailedStorageBusy) { 2536af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedStorageBusy; 2537af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else if (code == VoldResponseCode.OpFailedStorageNotFound) { 2538af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // If it's not mounted then we've already won. 2539af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationSucceeded; 2540af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 2541af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedInternalError; 2542a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2543a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 254438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2545af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (rc == StorageResultCode.OperationSucceeded) { 2546af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 25474fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey removeObbStateLocked(existingState); 2548af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 254938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2550af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED); 255138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } else { 25524fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Slog.w(TAG, "Could not unmount OBB: " + existingState); 2553af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT); 255438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2555a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2556a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 25575af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 2558a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleError() { 2559af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 2560a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2561a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2562a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 2563a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public String toString() { 2564a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root StringBuilder sb = new StringBuilder(); 2565a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("UnmountObbAction{"); 25664fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append(mObbState); 2567a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",force="); 2568a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mForceUnmount); 2569a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append('}'); 2570a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return sb.toString(); 2571a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 257202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 257338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 25744fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey // @VisibleForTesting 25754fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey public static String buildObbPath(final String canonicalPath, int userId, boolean forVold) { 25764fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey // TODO: allow caller to provide Environment for full testing 25774fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 25784fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey // Only adjust paths when storage is emulated 25794fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (!Environment.isExternalStorageEmulated()) { 25804fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return canonicalPath; 25814fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 25824fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 25834fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey String path = canonicalPath.toString(); 25844fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 25854fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey // First trim off any external storage prefix 25864fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final UserEnvironment userEnv = new UserEnvironment(userId); 25874fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 25884fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey // /storage/emulated/0 25894fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final String externalPath = userEnv.getExternalStorageDirectory().toString(); 25904fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey // /storage/emulated_legacy 25914fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final String legacyExternalPath = Environment.getLegacyExternalStorageDirectory() 25924fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey .toString(); 25934fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 25944fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (path.startsWith(externalPath)) { 25954fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey path = path.substring(externalPath.length() + 1); 25964fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } else if (path.startsWith(legacyExternalPath)) { 25974fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey path = path.substring(legacyExternalPath.length() + 1); 25984fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } else { 25994fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return canonicalPath; 26004fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 26014fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 26024fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey // Handle special OBB paths on emulated storage 26034fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final String obbPath = "Android/obb"; 26044fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (path.startsWith(obbPath)) { 26054fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey path = path.substring(obbPath.length() + 1); 26064fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 26074fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (forVold) { 26084fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return new File(Environment.getEmulatedStorageObbSource(), path).toString(); 26094fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } else { 26104fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final UserEnvironment ownerEnv = new UserEnvironment(UserHandle.USER_OWNER); 26114fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return new File(ownerEnv.getExternalStorageObbDirectory(), path).toString(); 26124fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 26134fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 26144fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 26154fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey // Handle normal external storage paths 26164fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (forVold) { 26174fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return new File(Environment.getEmulatedStorageSource(userId), path).toString(); 26184fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } else { 26194fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return new File(userEnv.getExternalStorageDirectory(), path).toString(); 26204fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 26214fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 26224fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 262338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root @Override 262438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 262538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { 262638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root pw.println("Permission Denial: can't dump ActivityManager from from pid=" 262738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() 262838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root + " without permission " + android.Manifest.permission.DUMP); 262938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return; 263038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 263138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 263238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root synchronized (mObbMounts) { 2633af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(" mObbMounts:"); 263438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2635af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet().iterator(); 2636af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (binders.hasNext()) { 2637af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Entry<IBinder, List<ObbState>> e = binders.next(); 2638af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" Key="); pw.println(e.getKey().toString()); 2639af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStates = e.getValue(); 264038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root for (final ObbState obbState : obbStates) { 2641af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" "); pw.println(obbState.toString()); 264238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 264338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2644af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2645af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(""); 2646af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(" mObbPathToStateMap:"); 2647af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator(); 2648af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (maps.hasNext()) { 2649af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Entry<String, ObbState> e = maps.next(); 2650af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" "); pw.print(e.getKey()); 2651af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" -> "); pw.println(e.getValue().toString()); 2652af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 265338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 26544161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root 26554161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root pw.println(""); 26564161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root 2657b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 26584161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root pw.println(" mVolumes:"); 26594161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root 26604161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root final int N = mVolumes.size(); 26614161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root for (int i = 0; i < N; i++) { 26624161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root final StorageVolume v = mVolumes.get(i); 26634161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root pw.print(" "); 26644161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root pw.println(v.toString()); 26654161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root } 26664161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root } 2667470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt 2668470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt pw.println(); 2669470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt pw.println(" mConnection:"); 2670470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt mConnector.dump(fd, pw, args); 267138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 26729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2673fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey /** {@inheritDoc} */ 2674fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey public void monitor() { 2675fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey if (mConnector != null) { 2676fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey mConnector.monitor(); 2677fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey } 2678fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey } 2679fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey} 2680