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 608b2c3a14603d163d7564e6f60286995079687690Jeff Sharkeyimport com.android.internal.annotations.GuardedBy; 618b2c3a14603d163d7564e6f60286995079687690Jeff Sharkeyimport com.android.internal.annotations.VisibleForTesting; 62b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.internal.app.IMediaContainerService; 634fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkeyimport com.android.internal.util.Preconditions; 64b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.internal.util.XmlUtils; 65b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.server.NativeDaemonConnector.Command; 66b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.server.am.ActivityManagerService; 67b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.server.pm.PackageManagerService; 68b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.server.pm.UserManagerService; 69b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.google.android.collect.Lists; 70b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.google.android.collect.Maps; 71b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 722f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport org.xmlpull.v1.XmlPullParserException; 73a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 74b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport java.io.File; 7538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.FileDescriptor; 7605105f7abe02b2dff91d6260b3628c8b97816babKenny Rootimport java.io.IOException; 7738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.PrintWriter; 783b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.math.BigInteger; 79735de3b38abbd6564082a819377673ee593744a6Kenny Rootimport java.security.NoSuchAlgorithmException; 803b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.InvalidKeySpecException; 813b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.KeySpec; 8222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehatimport java.util.ArrayList; 83a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.HashMap; 846cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehatimport java.util.HashSet; 8538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Iterator; 86a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.LinkedList; 87a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.List; 88a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.Map; 8938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Map.Entry; 9051a573c76737733638c475f52e441c814e6645ccKenny Rootimport java.util.concurrent.CountDownLatch; 9151a573c76737733638c475f52e441c814e6645ccKenny Rootimport java.util.concurrent.TimeUnit; 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 933b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKey; 943b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKeyFactory; 953b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.spec.PBEKeySpec; 963b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 98b104340496e3a531e26c8f428c808eca0e039f50San Mehat * MountService implements back-end services for platform storage 99b104340496e3a531e26c8f428c808eca0e039f50San Mehat * management. 100b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @hide - Applications should use android.os.storage.StorageManager 101b104340496e3a531e26c8f428c808eca0e039f50San Mehat * to access the MountService. 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 103fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkeyclass MountService extends IMountService.Stub 104fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey implements INativeDaemonConnectorCallbacks, Watchdog.Monitor { 1055af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 106b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // TODO: listen for user creation/deletion 107b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 10840e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn private static final boolean LOCAL_LOGD = false; 10940e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn private static final boolean DEBUG_UNMOUNT = false; 11040e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn private static final boolean DEBUG_EVENTS = false; 111b7db2726e91f1d9480359d0f83b9cb7769906b34Kenny Root private static final boolean DEBUG_OBB = false; 11202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 11307714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root // Disable this since it messes up long-running cryptfs operations. 11407714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root private static final boolean WATCHDOG_ENABLE = false; 11507714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String TAG = "MountService"; 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 118305bcbf0c961840c4505770d084a1caacc074dbbKenny Root private static final String VOLD_TAG = "VoldConnector"; 119305bcbf0c961840c4505770d084a1caacc074dbbKenny Root 120cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root /** Maximum number of ASEC containers allowed to be mounted. */ 121cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root private static final int MAX_CONTAINERS = 250; 122cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root 1234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Internal vold volume state constants 1254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 1267fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat class VolumeState { 1277fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Init = -1; 1287fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int NoMedia = 0; 1297fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Idle = 1; 1307fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Pending = 2; 1317fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Checking = 3; 1327fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Mounted = 4; 1337fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Unmounting = 5; 1347fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Formatting = 6; 1357fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Shared = 7; 1367fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int SharedMnt = 8; 1377fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 1387fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 1394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Internal vold response code constants 1414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 14222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat class VoldResponseCode { 1434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 100 series - Requestion action was initiated; expect another reply 1454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * before proceeding with a new command. 1464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 14722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeListResult = 110; 14822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int AsecListResult = 111; 149c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat public static final int StorageUsersListResult = 112; 15022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 200 series - Requestion action has been successfully completed. 1534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 1544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int ShareStatusResult = 210; 15522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int AsecPathResult = 211; 1564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int ShareEnabledResult = 212; 15722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 400 series - Command was accepted, but the requested action 1604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * did not take place. 1614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 1624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedNoMedia = 401; 1634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedMediaBlank = 402; 1644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedMediaCorrupt = 403; 1654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedVolNotMounted = 404; 166d970998b0d489774ad1c5b94b47d233912f00214San Mehat public static final int OpFailedStorageBusy = 405; 1672d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat public static final int OpFailedStorageNotFound = 406; 1684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 600 series - Unsolicited broadcasts. 1714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 17222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeStateChange = 605; 17322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeDiskInserted = 630; 17422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeDiskRemoved = 631; 17522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeBadRemoval = 632; 17622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 17722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 178b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private Context mContext; 179b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private NativeDaemonConnector mConnector; 180b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 181b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private final Object mVolumesLock = new Object(); 182b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 183b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey /** When defined, base template for user-specific {@link StorageVolume}. */ 184b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private StorageVolume mEmulatedTemplate; 185b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1868b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey @GuardedBy("mVolumesLock") 187b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private final ArrayList<StorageVolume> mVolumes = Lists.newArrayList(); 188b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey /** Map from path to {@link StorageVolume} */ 1898b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey @GuardedBy("mVolumesLock") 190b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private final HashMap<String, StorageVolume> mVolumesByPath = Maps.newHashMap(); 191b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey /** Map from path to state */ 1928b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey @GuardedBy("mVolumesLock") 193b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private final HashMap<String, String> mVolumeStates = Maps.newHashMap(); 194b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 195b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private volatile boolean mSystemReady = false; 196b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private PackageManagerService mPms; 1984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private boolean mUmsEnabling; 199ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood private boolean mUmsAvailable = false; 2000eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Used as a lock for methods that register/unregister listeners. 2010eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu final private ArrayList<MountServiceBinderListener> mListeners = 2020eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu new ArrayList<MountServiceBinderListener>(); 2030be607cda1aed67149963a1f602f399c79845cfdJeff Sharkey private final CountDownLatch mConnectedSignal = new CountDownLatch(1); 2040be607cda1aed67149963a1f602f399c79845cfdJeff Sharkey private final CountDownLatch mAsecsScanned = new CountDownLatch(1); 2056a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private boolean mSendUmsConnectedOnBoot = false; 206fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapu 2076cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat /** 2086cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat * Private hash of currently mounted secure containers. 2090eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * Used as a lock in methods to manipulate secure containers. 2106cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat */ 2110eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu final private HashSet<String> mAsecMountSet = new HashSet<String>(); 2126cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 21302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root /** 2143b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * The size of the crypto algorithm key in bits for OBB files. Currently 2153b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * Twofish is used which takes 128-bit keys. 2163b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root */ 2173b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128; 2183b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 2193b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root /** 2203b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * The number of times to run SHA1 in the PBKDF2 function for OBB files. 2213b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * 1024 is reasonably secure and not too slow. 2223b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root */ 2233b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root private static final int PBKDF2_HASH_ROUNDS = 1024; 2243b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 2253b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root /** 226a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * Mounted OBB tracking information. Used to track the current state of all 227a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * OBBs. 228a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root */ 229735de3b38abbd6564082a819377673ee593744a6Kenny Root final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>(); 2304fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 2314fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey /** Map from raw paths to {@link ObbState}. */ 232a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>(); 233a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 234a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class ObbState implements IBinder.DeathRecipient { 2354fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey public ObbState(String rawPath, String canonicalPath, int callingUid, 2364fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey IObbActionListener token, int nonce) { 2374fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey this.rawPath = rawPath; 2384fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey this.canonicalPath = canonicalPath.toString(); 2394fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 2404fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final int userId = UserHandle.getUserId(callingUid); 2414fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey this.ownerPath = buildObbPath(canonicalPath, userId, false); 2424fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey this.voldPath = buildObbPath(canonicalPath, userId, true); 2434fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 2444fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey this.ownerGid = UserHandle.getSharedAppGid(callingUid); 245af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root this.token = token; 246af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root this.nonce = nonce; 247a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 248a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2494fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final String rawPath; 2504fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final String canonicalPath; 2514fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final String ownerPath; 2524fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final String voldPath; 253a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2544fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final int ownerGid; 255a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 256af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Token of remote Binder caller 257af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IObbActionListener token; 258af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 259af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Identifier to pass back to the token 260af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final int nonce; 261a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 262735de3b38abbd6564082a819377673ee593744a6Kenny Root public IBinder getBinder() { 263735de3b38abbd6564082a819377673ee593744a6Kenny Root return token.asBinder(); 264735de3b38abbd6564082a819377673ee593744a6Kenny Root } 265735de3b38abbd6564082a819377673ee593744a6Kenny Root 266a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 267a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void binderDied() { 268a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbAction action = new UnmountObbAction(this, true); 269a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 270735de3b38abbd6564082a819377673ee593744a6Kenny Root } 271a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2725919ac6b4188285324646772501ef4b97b353cf4Kenny Root public void link() throws RemoteException { 2735919ac6b4188285324646772501ef4b97b353cf4Kenny Root getBinder().linkToDeath(this, 0); 2745919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 2755919ac6b4188285324646772501ef4b97b353cf4Kenny Root 2765919ac6b4188285324646772501ef4b97b353cf4Kenny Root public void unlink() { 277735de3b38abbd6564082a819377673ee593744a6Kenny Root getBinder().unlinkToDeath(this, 0); 278a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 27938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 28038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root @Override 28138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root public String toString() { 28238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root StringBuilder sb = new StringBuilder("ObbState{"); 2834fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append("rawPath=").append(rawPath); 2844fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append(",canonicalPath=").append(canonicalPath); 2854fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append(",ownerPath=").append(ownerPath); 2864fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append(",voldPath=").append(voldPath); 2874fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append(",ownerGid=").append(ownerGid); 2884fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append(",token=").append(token); 2894fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append(",binder=").append(getBinder()); 29038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append('}'); 29138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return sb.toString(); 29238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 293a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 294a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 295a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // OBB Action Handler 296a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private ObbActionHandler mObbActionHandler; 297a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 298a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // OBB action handler messages 299a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_RUN_ACTION = 1; 300a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_BOUND = 2; 301a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_UNBIND = 3; 302a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_RECONNECT = 4; 303af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private static final int OBB_FLUSH_MOUNT_STATE = 5; 304a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 305a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root /* 306a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * Default Container Service information 30702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root */ 308a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName( 309a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService"); 310a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 311a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection(); 312a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 313a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class DefaultContainerConnection implements ServiceConnection { 314a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void onServiceConnected(ComponentName name, IBinder service) { 315a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 316a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "onServiceConnected"); 317a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service); 318a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs)); 319a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 320a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 321a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void onServiceDisconnected(ComponentName name) { 322a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 323a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "onServiceDisconnected"); 324a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 325a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root }; 326a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 327a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Used in the ObbActionHandler 328a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private IMediaContainerService mContainerService = null; 32902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 33002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root // Handler messages 331c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_PM_UPDATE = 1; 332c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_PM_DONE = 2; 333c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_MS = 3; 334b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private static final int H_SYSTEM_READY = 4; 335b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 336c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int RETRY_UNMOUNT_DELAY = 30; // in ms 337c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int MAX_UNMOUNT_RETRIES = 4; 338c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 339c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu class UnmountCallBack { 34005105f7abe02b2dff91d6260b3628c8b97816babKenny Root final String path; 34105105f7abe02b2dff91d6260b3628c8b97816babKenny Root final boolean force; 34213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo final boolean removeEncryption; 343c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu int retries; 344c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 34513c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo UnmountCallBack(String path, boolean force, boolean removeEncryption) { 346c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu retries = 0; 347c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu this.path = path; 348c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu this.force = force; 34913c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo this.removeEncryption = removeEncryption; 350c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 3510eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3520eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu void handleFinished() { 353a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path); 35413c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo doUnmountVolume(path, true, removeEncryption); 3550eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 3560eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 3570eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3580eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu class UmsEnableCallBack extends UnmountCallBack { 35905105f7abe02b2dff91d6260b3628c8b97816babKenny Root final String method; 3600eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3610eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu UmsEnableCallBack(String path, String method, boolean force) { 36213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo super(path, force, false); 3630eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu this.method = method; 3640eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 3650eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3660eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu @Override 3670eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu void handleFinished() { 3680eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu super.handleFinished(); 3690eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doShareUnshareVolume(path, method, true); 3700eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 371c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 372c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 3736ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu class ShutdownCallBack extends UnmountCallBack { 3746ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu IMountShutdownObserver observer; 3756ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu ShutdownCallBack(String path, IMountShutdownObserver observer) { 37613c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo super(path, true, false); 3776ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu this.observer = observer; 3786ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3796ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3806ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu @Override 3816ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu void handleFinished() { 38213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo int ret = doUnmountVolume(path, true, removeEncryption); 3836ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (observer != null) { 3846ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu try { 3856ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu observer.onShutDownComplete(ret); 3866ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } catch (RemoteException e) { 387a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "RemoteException when shutting down"); 3886ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3896ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3906ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3916ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3926ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3935f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler class MountServiceHandler extends Handler { 394c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>(); 395e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu boolean mUpdatingStatus = false; 3966ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3975f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler MountServiceHandler(Looper l) { 3985f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler super(l); 3995f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler } 4005f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler 4015af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 402c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu public void handleMessage(Message msg) { 403c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu switch (msg.what) { 404c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_PM_UPDATE: { 405a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_UPDATE"); 406c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = (UnmountCallBack) msg.obj; 407c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu mForceUnmounts.add(ucb); 408a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, " registered = " + mUpdatingStatus); 4096ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Register only if needed. 410e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu if (!mUpdatingStatus) { 411a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Updating external media status on PackageManager"); 412e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mUpdatingStatus = true; 413e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(false, true); 414c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 415c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 416c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 417c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_PM_DONE: { 418a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_DONE"); 419a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Updated status. Processing requests"); 420e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mUpdatingStatus = false; 4216ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int size = mForceUnmounts.size(); 4226ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int sizeArr[] = new int[size]; 4236ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int sizeArrN = 0; 4247af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Kill processes holding references first 4257af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ActivityManagerService ams = (ActivityManagerService) 4267af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ServiceManager.getService("activity"); 4276ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu for (int i = 0; i < size; i++) { 4286ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu UnmountCallBack ucb = mForceUnmounts.get(i); 4296ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu String path = ucb.path; 4306ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu boolean done = false; 4316ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (!ucb.force) { 432c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu done = true; 433c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } else { 4346ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int pids[] = getStorageUsers(path); 4356ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (pids == null || pids.length == 0) { 4366ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu done = true; 4376ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } else { 4386ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Eliminate system process here? 439648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn ams.killPids(pids, "unmount media", true); 4407af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Confirm if file references have been freed. 4417af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu pids = getStorageUsers(path); 4427af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu if (pids == null || pids.length == 0) { 4437af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu done = true; 444c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 445c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 446c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 4477af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) { 4487af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Retry again 4497af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu Slog.i(TAG, "Retrying to kill storage users again"); 4507af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.sendMessageDelayed( 4517af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.obtainMessage(H_UNMOUNT_PM_DONE, 4527af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ucb.retries++), 4537af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu RETRY_UNMOUNT_DELAY); 454c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } else { 4556ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (ucb.retries >= MAX_UNMOUNT_RETRIES) { 4567af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu Slog.i(TAG, "Failed to unmount media inspite of " + 4577af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu MAX_UNMOUNT_RETRIES + " retries. Forcibly killing processes now"); 4586ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 4597af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu sizeArr[sizeArrN++] = i; 4607af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS, 4617af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ucb)); 462c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 463c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 4646ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Remove already processed elements from list. 4656ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu for (int i = (sizeArrN-1); i >= 0; i--) { 4666ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu mForceUnmounts.remove(sizeArr[i]); 4676ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 468c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 469c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 470b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey case H_UNMOUNT_MS: { 471a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_MS"); 472c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = (UnmountCallBack) msg.obj; 4730eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu ucb.handleFinished(); 474c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 475c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 476b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey case H_SYSTEM_READY: { 477b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey try { 478b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey handleSystemReady(); 479b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } catch (Exception ex) { 480b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Slog.e(TAG, "Boot-time mount exception", ex); 481b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 482b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey break; 483b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 484c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 485c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 486c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu }; 487b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 488b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private final HandlerThread mHandlerThread; 489b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private final Handler mHandler; 490c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 49151a573c76737733638c475f52e441c814e6645ccKenny Root void waitForAsecScan() { 49251a573c76737733638c475f52e441c814e6645ccKenny Root waitForLatch(mAsecsScanned); 49351a573c76737733638c475f52e441c814e6645ccKenny Root } 49451a573c76737733638c475f52e441c814e6645ccKenny Root 495207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void waitForReady() { 49651a573c76737733638c475f52e441c814e6645ccKenny Root waitForLatch(mConnectedSignal); 49751a573c76737733638c475f52e441c814e6645ccKenny Root } 49851a573c76737733638c475f52e441c814e6645ccKenny Root 49951a573c76737733638c475f52e441c814e6645ccKenny Root private void waitForLatch(CountDownLatch latch) { 50051a573c76737733638c475f52e441c814e6645ccKenny Root for (;;) { 50151a573c76737733638c475f52e441c814e6645ccKenny Root try { 50251a573c76737733638c475f52e441c814e6645ccKenny Root if (latch.await(5000, TimeUnit.MILLISECONDS)) { 503207e538350665cea00e1aa70b8094beca4a34e45San Mehat return; 50451a573c76737733638c475f52e441c814e6645ccKenny Root } else { 50551a573c76737733638c475f52e441c814e6645ccKenny Root Slog.w(TAG, "Thread " + Thread.currentThread().getName() 50651a573c76737733638c475f52e441c814e6645ccKenny Root + " still waiting for MountService ready..."); 507207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 50851a573c76737733638c475f52e441c814e6645ccKenny Root } catch (InterruptedException e) { 50951a573c76737733638c475f52e441c814e6645ccKenny Root Slog.w(TAG, "Interrupt while waiting for MountService to be ready."); 510207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 511207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 5121f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 51302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 514b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private void handleSystemReady() { 515b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // Snapshot current volume states since it's not safe to call into vold 516b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // while holding locks. 517b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final HashMap<String, String> snapshot; 518b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 519b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey snapshot = new HashMap<String, String>(mVolumeStates); 520b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 52191c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 522b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey for (Map.Entry<String, String> entry : snapshot.entrySet()) { 523b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final String path = entry.getKey(); 524b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final String state = entry.getValue(); 52522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 526b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (state.equals(Environment.MEDIA_UNMOUNTED)) { 527b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey int rc = doMountVolume(path); 528b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (rc != StorageResultCode.OperationSucceeded) { 529b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Slog.e(TAG, String.format("Boot-time mount failed (%d)", 530b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey rc)); 531b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 532b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } else if (state.equals(Environment.MEDIA_SHARED)) { 533c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen /* 534b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * Bootstrap UMS enabled state since vold indicates 535b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * the volume is shared (runtime restart while ums enabled) 536c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen */ 537b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey notifyVolumeStateChange(null, path, VolumeState.NoMedia, 538b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey VolumeState.Shared); 539b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 540b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 541b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 542b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // Push mounted state for all emulated storage 543b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 544b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey for (StorageVolume volume : mVolumes) { 545b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (volume.isEmulated()) { 546b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED); 547c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen } 548b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 549b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 55084338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood 551b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey /* 552b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * If UMS was connected on boot, send the connected event 553b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * now that we're up. 554b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey */ 555b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (mSendUmsConnectedOnBoot) { 556b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey sendUmsIntent(true); 557b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mSendUmsConnectedOnBoot = false; 558b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 559b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 5606a254403235196692b1769d2fe281b0852c0cc25San Mehat 561b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() { 562b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey @Override 563b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey public void onReceive(Context context, Intent intent) { 564b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); 565b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (userId == -1) return; 566b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final UserHandle user = new UserHandle(userId); 567b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 568b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final String action = intent.getAction(); 569b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (Intent.ACTION_USER_ADDED.equals(action)) { 570b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 571b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey createEmulatedVolumeForUserLocked(user); 572b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 573b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 574b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } else if (Intent.ACTION_USER_REMOVED.equals(action)) { 575b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 576b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final List<StorageVolume> toRemove = Lists.newArrayList(); 577b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey for (StorageVolume volume : mVolumes) { 578b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (user.equals(volume.getOwner())) { 579b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey toRemove.add(volume); 580fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } 581207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 582b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey for (StorageVolume volume : toRemove) { 583b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey removeVolumeLocked(volume); 584b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 585b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 589b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 590b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { 591b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey @Override 592b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey public void onReceive(Context context, Intent intent) { 593b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey boolean available = (intent.getBooleanExtra(UsbManager.USB_CONNECTED, false) && 594b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey intent.getBooleanExtra(UsbManager.USB_FUNCTION_MASS_STORAGE, false)); 595b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey notifyShareAvailabilityChange(available); 596b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 597b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey }; 598b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 5994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private final class MountServiceBinderListener implements IBinder.DeathRecipient { 6004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final IMountServiceListener mListener; 60191c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 6024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener(IMountServiceListener listener) { 6034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListener = listener; 60402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 60591c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 60691c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 6074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void binderDied() { 608a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!"); 609a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root synchronized (mListeners) { 6104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(this); 6114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListener.asBinder().unlinkToDeath(this, 0); 61291c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 61391c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 61491c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 61591c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 6160eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private void doShareUnshareVolume(String path, String method, boolean enable) { 6174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat // TODO: Add support for multiple share methods 6184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!method.equals("ums")) { 6194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new IllegalArgumentException(String.format("Method %s not supported", method)); 6207fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 623dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("volume", enable ? "share" : "unshare", path, method); 6244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 625a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to share/unshare", e); 62622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 629b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private void updatePublicVolumeState(StorageVolume volume, String state) { 630b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final String path = volume.getPath(); 631b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final String oldState; 632b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 6337fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood oldState = mVolumeStates.put(path, state); 6347fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 635b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 6367fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state.equals(oldState)) { 6377fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.w(TAG, String.format("Duplicate state transition (%s -> %s) for %s", 6387fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood state, state, path)); 639b104340496e3a531e26c8f428c808eca0e039f50San Mehat return; 640b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 641af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 6427fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.d(TAG, "volume state changed for " + path + " (" + oldState + " -> " + state + ")"); 6437fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 644b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // Tell PackageManager about changes to primary volume state, but only 645b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // when not emulated. 646b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (volume.isPrimary() && !volume.isEmulated()) { 647b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (Environment.MEDIA_UNMOUNTED.equals(state)) { 648b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mPms.updateExternalMediaStatus(false, false); 6497fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 650b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey /* 651b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * Some OBBs might have been unmounted when this volume was 652b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * unmounted, so send a message to the handler to let it know to 653b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * remove those from the list of mounted OBBS. 654b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey */ 655b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage( 656b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey OBB_FLUSH_MOUNT_STATE, path)); 657b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } else if (Environment.MEDIA_MOUNTED.equals(state)) { 658b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mPms.updateExternalMediaStatus(true, false); 65903559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood } 6608a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 661b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 6624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 6634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for (int i = mListeners.size() -1; i >= 0; i--) { 6644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = mListeners.get(i); 6654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 666b104340496e3a531e26c8f428c808eca0e039f50San Mehat bl.mListener.onStorageStateChanged(path, oldState, state); 6674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 668a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener dead"); 6694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(i); 6704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 671a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener failed", ex); 6724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 67722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat /** 67822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * Callback from NativeDaemonConnector 67922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat */ 68022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public void onDaemonConnected() { 6815b77dab23469273d41f9c530d947ac055765e6eaSan Mehat /* 6825b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * Since we'll be calling back into the NativeDaemonConnector, 6835b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * we need to do our work in a new thread. 6845b77dab23469273d41f9c530d947ac055765e6eaSan Mehat */ 68551a573c76737733638c475f52e441c814e6645ccKenny Root new Thread("MountService#onDaemonConnected") { 6865af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 6877fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public void run() { 6885b77dab23469273d41f9c530d947ac055765e6eaSan Mehat /** 6895b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * Determine media state and UMS detection status 6905b77dab23469273d41f9c530d947ac055765e6eaSan Mehat */ 6917fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat try { 692dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final String[] vols = NativeDaemonEvent.filterMessageList( 693dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.executeForList("volume", "list"), 694dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey VoldResponseCode.VolumeListResult); 6955b77dab23469273d41f9c530d947ac055765e6eaSan Mehat for (String volstr : vols) { 6965b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String[] tok = volstr.split(" "); 6975b77dab23469273d41f9c530d947ac055765e6eaSan Mehat // FMT: <label> <mountpoint> <state> 6987fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String path = tok[1]; 6997fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String state = Environment.MEDIA_REMOVED; 7007fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 701b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume volume; 702b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 703b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey volume = mVolumesByPath.get(path); 704b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 705b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 7065b77dab23469273d41f9c530d947ac055765e6eaSan Mehat int st = Integer.parseInt(tok[2]); 7075b77dab23469273d41f9c530d947ac055765e6eaSan Mehat if (st == VolumeState.NoMedia) { 7085b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_REMOVED; 7095b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Idle) { 710207e538350665cea00e1aa70b8094beca4a34e45San Mehat state = Environment.MEDIA_UNMOUNTED; 7115b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Mounted) { 7125b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_MOUNTED; 713a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Media already mounted on daemon connection"); 7145b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Shared) { 7155b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_SHARED; 716a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Media shared on daemon connection"); 7175b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else { 7185b77dab23469273d41f9c530d947ac055765e6eaSan Mehat throw new Exception(String.format("Unexpected state %d", st)); 7197fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 7207fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 7217fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state != null) { 7227fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state); 723b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, state); 7247fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 725c2a39471642e31d7350910612e40d078b825173aSan Mehat } 7265b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } catch (Exception e) { 727a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Error processing initial volume state", e); 728b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume primary = getPrimaryPhysicalVolume(); 729b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (primary != null) { 730b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(primary, Environment.MEDIA_REMOVED); 731b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 7327fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 7337fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 734207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 7359ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks * Now that we've done our initialization, release 736207e538350665cea00e1aa70b8094beca4a34e45San Mehat * the hounds! 737207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 73851a573c76737733638c475f52e441c814e6645ccKenny Root mConnectedSignal.countDown(); 73951a573c76737733638c475f52e441c814e6645ccKenny Root 74051a573c76737733638c475f52e441c814e6645ccKenny Root // Let package manager load internal ASECs. 74151a573c76737733638c475f52e441c814e6645ccKenny Root mPms.scanAvailableAsecs(); 74251a573c76737733638c475f52e441c814e6645ccKenny Root 74351a573c76737733638c475f52e441c814e6645ccKenny Root // Notify people waiting for ASECs to be scanned that it's done. 74451a573c76737733638c475f52e441c814e6645ccKenny Root mAsecsScanned.countDown(); 7457fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 7467fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat }.start(); 7477fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 7487fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 74922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat /** 75022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * Callback from NativeDaemonConnector 75122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat */ 75222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public boolean onEvent(int code, String raw, String[] cooked) { 7538a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (DEBUG_EVENTS) { 7548a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu StringBuilder builder = new StringBuilder(); 7558a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append("onEvent::"); 7568a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" raw= " + raw); 7578a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (cooked != null) { 7588a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" cooked = " ); 7598a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu for (String str : cooked) { 7608a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" " + str); 7618a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 7628a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 763a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, builder.toString()); 7648a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 76522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat if (code == VoldResponseCode.VolumeStateChange) { 7664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 7674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * One of the volumes we're managing has changed state. 7684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Format: "NNN Volume <label> <path> state changed 7694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * from <old_#> (<old_str>) to <new_#> (<new_str>)" 7704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 77122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat notifyVolumeStateChange( 77222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat cooked[2], cooked[3], Integer.parseInt(cooked[7]), 77322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat Integer.parseInt(cooked[10])); 7744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if ((code == VoldResponseCode.VolumeDiskInserted) || 7754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat (code == VoldResponseCode.VolumeDiskRemoved) || 7764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat (code == VoldResponseCode.VolumeBadRemoval)) { 77722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>) 77822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>) 77922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>) 780a5250c93928e256738125b265e10c96c3575597eMike Lockwood String action = null; 7814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final String label = cooked[2]; 7824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final String path = cooked[3]; 7834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int major = -1; 7844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int minor = -1; 7854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 7864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 7874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String devComp = cooked[6].substring(1, cooked[6].length() -1); 7884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String[] devTok = devComp.split(":"); 7894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat major = Integer.parseInt(devTok[0]); 7904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat minor = Integer.parseInt(devTok[1]); 7914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 792a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to parse major/minor", ex); 7934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 795b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume volume; 796b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final String state; 797b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 798b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey volume = mVolumesByPath.get(path); 799b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey state = mVolumeStates.get(path); 800b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 801b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 8024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (code == VoldResponseCode.VolumeDiskInserted) { 8034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat new Thread() { 8045af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 8054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void run() { 8064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 8074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int rc; 808b104340496e3a531e26c8f428c808eca0e039f50San Mehat if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { 809a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, String.format("Insertion mount failed (%d)", rc)); 8104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 8114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 812a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Failed to mount media on insertion", ex); 8134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 8144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 8154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat }.start(); 8164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (code == VoldResponseCode.VolumeDiskRemoved) { 8174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 8184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * This event gets trumped if we're already in BAD_REMOVAL state 8194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 8204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) { 8214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return true; 8224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 8234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 824a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first"); 825b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED); 826b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey sendStorageIntent(Environment.MEDIA_UNMOUNTED, volume, UserHandle.ALL); 8274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 828a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed"); 829b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_REMOVED); 830a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_REMOVED; 8314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (code == VoldResponseCode.VolumeBadRemoval) { 832a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first"); 8334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 834b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED); 835a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_UNMOUNTED; 8364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 837a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal"); 838b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_BAD_REMOVAL); 839a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_BAD_REMOVAL; 8404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else { 841a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Unknown code {%d}", code)); 8424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 843a5250c93928e256738125b265e10c96c3575597eMike Lockwood 844a5250c93928e256738125b265e10c96c3575597eMike Lockwood if (action != null) { 845b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey sendStorageIntent(action, volume, UserHandle.ALL); 846a5250c93928e256738125b265e10c96c3575597eMike Lockwood } 84722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else { 84822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat return false; 84922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 8504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 8515f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler return true; 85222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 85322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 854207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void notifyVolumeStateChange(String label, String path, int oldState, int newState) { 855b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume volume; 856b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final String state; 857b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 858b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey volume = mVolumesByPath.get(path); 859b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey state = getVolumeState(path); 860b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 861b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 862b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChange::" + state); 8634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 864a5250c93928e256738125b265e10c96c3575597eMike Lockwood String action = null; 8657fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 866bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood if (oldState == VolumeState.Shared && newState != oldState) { 867a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent"); 868b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey sendStorageIntent(Intent.ACTION_MEDIA_UNSHARED, volume, UserHandle.ALL); 869bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood } 870bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood 8717fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat if (newState == VolumeState.Init) { 8727fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.NoMedia) { 8737fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat // NoMedia is handled via Disk Remove events 8747fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Idle) { 8755fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat /* 8765fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or 8775fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat * if we're in the process of enabling UMS 8785fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat */ 879b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (!state.equals( 880b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Environment.MEDIA_BAD_REMOVAL) && !state.equals( 881b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Environment.MEDIA_NOFS) && !state.equals( 8820eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) { 883a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable"); 884b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED); 885a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_UNMOUNTED; 8867fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 8877fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Pending) { 8887fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Checking) { 889a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking"); 890b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_CHECKING); 891a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_CHECKING; 8927fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Mounted) { 893a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted"); 894b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED); 895a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_MOUNTED; 8967fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Unmounting) { 897a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_EJECT; 8987fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Formatting) { 8997fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Shared) { 900a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted"); 9014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 902b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED); 903b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL); 9044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 905a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared"); 906b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_SHARED); 907a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_SHARED; 908a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent"); 9097fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.SharedMnt) { 910a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Live shared mounts not supported yet!"); 9114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return; 9127fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else { 913a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Unhandled VolumeState {" + newState + "}"); 9147fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 9157fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 916a5250c93928e256738125b265e10c96c3575597eMike Lockwood if (action != null) { 917b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey sendStorageIntent(action, volume, UserHandle.ALL); 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 921207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doMountVolume(String path) { 922b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 923207e538350665cea00e1aa70b8094beca4a34e45San Mehat 924b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume volume; 925b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 926b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey volume = mVolumesByPath.get(path); 927b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 928b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 929a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path); 930207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 931dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("volume", "mount", path); 932207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 933207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 934207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Mount failed for some reason 935207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 936a5250c93928e256738125b265e10c96c3575597eMike Lockwood String action = null; 937207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 938207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedNoMedia) { 939207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 940207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Attempt to mount but no media inserted 941207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 942b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedNoMedia; 943207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaBlank) { 944a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs"); 945207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 946207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Media is blank or does not contain a supported filesystem 947207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 948b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_NOFS); 949a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_NOFS; 950b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedMediaBlank; 951207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { 952a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state media corrupt"); 953207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 954207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Volume consistency check failed 955207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 956b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTABLE); 957a5250c93928e256738125b265e10c96c3575597eMike Lockwood action = Intent.ACTION_MEDIA_UNMOUNTABLE; 958b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedMediaCorrupt; 959207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 960b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 961207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 962207e538350665cea00e1aa70b8094beca4a34e45San Mehat 963207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 964207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Send broadcast intent (if required for the failure) 965207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 966a5250c93928e256738125b265e10c96c3575597eMike Lockwood if (action != null) { 967b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey sendStorageIntent(action, volume, UserHandle.ALL); 968207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 969207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 970207e538350665cea00e1aa70b8094beca4a34e45San Mehat 971207e538350665cea00e1aa70b8094beca4a34e45San Mehat return rc; 972207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 973207e538350665cea00e1aa70b8094beca4a34e45San Mehat 974c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu /* 975c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * If force is not set, we do not unmount if there are 976c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * processes holding references to the volume about to be unmounted. 977c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * If force is set, all the processes holding references need to be 978c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * killed via the ActivityManager before actually unmounting the volume. 979c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * This might even take a while and might be retried after timed delays 980c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * to make sure we dont end up in an instable state and kill some core 981c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * processes. 98213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo * If removeEncryption is set, force is implied, and the system will remove any encryption 98313c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo * mapping set on the volume when unmounting. 984c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu */ 98513c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo private int doUnmountVolume(String path, boolean force, boolean removeEncryption) { 98659443a673a736978361dc341f41ce4e9dae053a0San Mehat if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) { 987207e538350665cea00e1aa70b8094beca4a34e45San Mehat return VoldResponseCode.OpFailedVolNotMounted; 988207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 989aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 990aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 991aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 992aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 993aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 994aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 995aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 996aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 997aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 998c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu // Redundant probably. But no harm in updating state again. 999e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(false, false); 1000207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 1001dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final Command cmd = new Command("volume", "unmount", path); 1002dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey if (removeEncryption) { 1003dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey cmd.appendArg("force_and_revert"); 1004dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } else if (force) { 1005dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey cmd.appendArg("force"); 1006dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } 1007dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute(cmd); 1008e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu // We unmounted the volume. None of the asec containers are available now. 1009e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu synchronized (mAsecMountSet) { 1010e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mAsecMountSet.clear(); 1011e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu } 1012b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationSucceeded; 1013207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 1014207e538350665cea00e1aa70b8094beca4a34e45San Mehat // Don't worry about mismatch in PackageManager since the 1015207e538350665cea00e1aa70b8094beca4a34e45San Mehat // call back will handle the status changes any way. 1016207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 1017207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedVolNotMounted) { 1018a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageNotMounted; 1019d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else if (code == VoldResponseCode.OpFailedStorageBusy) { 1020d970998b0d489774ad1c5b94b47d233912f00214San Mehat return StorageResultCode.OperationFailedStorageBusy; 1021207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 1022b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedInternalError; 1023207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1024207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1025207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1026207e538350665cea00e1aa70b8094beca4a34e45San Mehat 1027207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doFormatVolume(String path) { 1028207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 1029dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("volume", "format", path); 1030b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationSucceeded; 1031207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 1032207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 1033207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedNoMedia) { 1034b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedNoMedia; 1035207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { 1036b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedMediaCorrupt; 1037207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 1038b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedInternalError; 1039207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1040207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1041207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1042207e538350665cea00e1aa70b8094beca4a34e45San Mehat 1043b104340496e3a531e26c8f428c808eca0e039f50San Mehat private boolean doGetVolumeShared(String path, String method) { 1044dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 1045a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root try { 1046dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("volume", "shared", path, method); 1047a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } catch (NativeDaemonConnectorException ex) { 1048a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root Slog.e(TAG, "Failed to read response to volume shared " + path + " " + method); 1049a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return false; 1050a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } 1051b104340496e3a531e26c8f428c808eca0e039f50San Mehat 1052dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey if (event.getCode() == VoldResponseCode.ShareEnabledResult) { 1053dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return event.getMessage().endsWith("enabled"); 1054dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } else { 1055dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return false; 1056b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1057b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1058b104340496e3a531e26c8f428c808eca0e039f50San Mehat 1059ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood private void notifyShareAvailabilityChange(final boolean avail) { 10604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 1061ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood mUmsAvailable = avail; 10624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for (int i = mListeners.size() -1; i >= 0; i--) { 10634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = mListeners.get(i); 10641f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat try { 1065b104340496e3a531e26c8f428c808eca0e039f50San Mehat bl.mListener.onUsbMassStorageConnectionChanged(avail); 10664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 1067a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener dead"); 10684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(i); 10691f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } catch (Exception ex) { 1070a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener failed", ex); 10711f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 10721f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 10734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 10747fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 1075b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (mSystemReady == true) { 10766a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat sendUmsIntent(avail); 10776a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } else { 10786a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat mSendUmsConnectedOnBoot = avail; 10791f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 10802fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat 1081b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume primary = getPrimaryPhysicalVolume(); 1082b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (avail == false && primary != null 1083b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey && Environment.MEDIA_SHARED.equals(getVolumeState(primary.getPath()))) { 1084b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final String path = primary.getPath(); 10852fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat /* 10862fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat * USB mass storage disconnected while enabled 10872fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat */ 10882fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat new Thread() { 10895af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 10902fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat public void run() { 10912fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat try { 10922fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat int rc; 1093a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Disabling UMS after cable disconnect"); 10942fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat doShareUnshareVolume(path, "ums", false); 10952fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { 1096a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format( 10972fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat "Failed to remount {%s} on UMS enabled-disconnect (%d)", 10982fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat path, rc)); 10992fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 11002fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } catch (Exception ex) { 1101a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Failed to mount media on UMS enabled-disconnect", ex); 11022fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 11032fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 11042fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat }.start(); 11052fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1108b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private void sendStorageIntent(String action, StorageVolume volume, UserHandle user) { 1109b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final Intent intent = new Intent(action, Uri.parse("file://" + volume.getPath())); 1110b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, volume); 1111b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Slog.d(TAG, "sendStorageIntent " + intent + " to " + user); 1112b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mContext.sendBroadcastAsUser(intent, user); 1113a5250c93928e256738125b265e10c96c3575597eMike Lockwood } 1114a5250c93928e256738125b265e10c96c3575597eMike Lockwood 11156a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private void sendUmsIntent(boolean c) { 11165ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn mContext.sendBroadcastAsUser( 11175ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn new Intent((c ? Intent.ACTION_UMS_CONNECTED : Intent.ACTION_UMS_DISCONNECTED)), 11185ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn UserHandle.ALL); 11196a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } 11206a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat 1121207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void validatePermission(String perm) { 11224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) { 11234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new SecurityException(String.format("Requires %s permission", perm)); 11244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 11257fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 11267fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 11272f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood // Storage list XML tags 11282f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood private static final String TAG_STORAGE_LIST = "StorageList"; 11292f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood private static final String TAG_STORAGE = "storage"; 11302f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 1131b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private void readStorageListLocked() { 1132b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mVolumes.clear(); 1133b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mVolumeStates.clear(); 1134b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 113513fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio Resources resources = mContext.getResources(); 113613fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio 11372f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood int id = com.android.internal.R.xml.storage_list; 11382f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood XmlResourceParser parser = resources.getXml(id); 11392f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood AttributeSet attrs = Xml.asAttributeSet(parser); 11402f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 11412f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood try { 11422f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood XmlUtils.beginDocument(parser, TAG_STORAGE_LIST); 11432f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood while (true) { 11442f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood XmlUtils.nextElement(parser); 11452f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 11462f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood String element = parser.getName(); 11472f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (element == null) break; 11482f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 11492f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood if (TAG_STORAGE.equals(element)) { 11502f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood TypedArray a = resources.obtainAttributes(attrs, 11512f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage); 11522f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 1153b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey String path = a.getString( 11542f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_mountPoint); 115513fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio int descriptionId = a.getResourceId( 115613fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio com.android.internal.R.styleable.Storage_storageDescription, -1); 11572f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood CharSequence description = a.getText( 11582f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_storageDescription); 11592f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood boolean primary = a.getBoolean( 11602f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_primary, false); 11612f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood boolean removable = a.getBoolean( 11622f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_removable, false); 11632f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood boolean emulated = a.getBoolean( 11642f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_emulated, false); 11652f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood int mtpReserve = a.getInt( 11662f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood com.android.internal.R.styleable.Storage_mtpReserve, 0); 11678e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood boolean allowMassStorage = a.getBoolean( 11688e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood com.android.internal.R.styleable.Storage_allowMassStorage, false); 11697a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood // resource parser does not support longs, so XML value is in megabytes 11707a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood long maxFileSize = a.getInt( 11717a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood com.android.internal.R.styleable.Storage_maxFileSize, 0) * 1024L * 1024L; 11722f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 11732f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood Slog.d(TAG, "got storage path: " + path + " description: " + description + 11742f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood " primary: " + primary + " removable: " + removable + 11758e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood " emulated: " + emulated + " mtpReserve: " + mtpReserve + 11767a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood " allowMassStorage: " + allowMassStorage + 11777a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood " maxFileSize: " + maxFileSize); 1178b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1179b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (emulated) { 1180b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // For devices with emulated storage, we create separate 1181b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // volumes for each known user. 1182b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mEmulatedTemplate = new StorageVolume(null, descriptionId, true, false, 1183b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey true, mtpReserve, false, maxFileSize, null); 1184b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1185b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final UserManagerService userManager = UserManagerService.getInstance(); 1186920ace0bbc2d4133dbec991d2636c99a57d6245eAmith Yamasani for (UserInfo user : userManager.getUsers(false)) { 1187b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey createEmulatedVolumeForUserLocked(user.getUserHandle()); 11882f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 1189b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1190b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } else { 1191b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (path == null || description == null) { 1192b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Slog.e(TAG, "Missing storage path or description in readStorageList"); 11932f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } else { 1194b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume volume = new StorageVolume(new File(path), 1195b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey descriptionId, primary, removable, emulated, mtpReserve, 1196b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey allowMassStorage, maxFileSize, null); 1197b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey addVolumeLocked(volume); 11982f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 11992f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 1200b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 12012f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood a.recycle(); 12022f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 12032f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 12042f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } catch (XmlPullParserException e) { 12052f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood throw new RuntimeException(e); 12062f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } catch (IOException e) { 12072f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood throw new RuntimeException(e); 12082f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } finally { 1209b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // Compute storage ID for each physical volume; emulated storage is 1210b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // always 0 when defined. 1211b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey int index = isExternalStorageEmulated() ? 1 : 0; 1212b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey for (StorageVolume volume : mVolumes) { 1213b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (!volume.isEmulated()) { 1214b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey volume.setStorageId(index++); 1215b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1216fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood } 12172f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood parser.close(); 12182f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 12192f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood } 12202f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1222b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * Create and add new {@link StorageVolume} for given {@link UserHandle} 1223b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey * using {@link #mEmulatedTemplate} as template. 1224b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey */ 1225b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private void createEmulatedVolumeForUserLocked(UserHandle user) { 1226b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (mEmulatedTemplate == null) { 1227b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey throw new IllegalStateException("Missing emulated volume multi-user template"); 1228b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1229b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1230b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final UserEnvironment userEnv = new UserEnvironment(user.getIdentifier()); 1231b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final File path = userEnv.getExternalStorageDirectory(); 1232b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume volume = StorageVolume.fromTemplate(mEmulatedTemplate, path, user); 1233b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey volume.setStorageId(0); 1234b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey addVolumeLocked(volume); 1235b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1236b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (mSystemReady) { 1237b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED); 1238b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } else { 1239b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // Place stub status for early callers to find 1240b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mVolumeStates.put(volume.getPath(), Environment.MEDIA_MOUNTED); 1241b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1242b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1243b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1244b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private void addVolumeLocked(StorageVolume volume) { 1245b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Slog.d(TAG, "addVolumeLocked() " + volume); 1246b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mVolumes.add(volume); 1247b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume existing = mVolumesByPath.put(volume.getPath(), volume); 1248b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (existing != null) { 1249b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey throw new IllegalStateException( 1250b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey "Volume at " + volume.getPath() + " already exists: " + existing); 1251b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1252b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1253b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1254b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private void removeVolumeLocked(StorageVolume volume) { 1255b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Slog.d(TAG, "removeVolumeLocked() " + volume); 1256b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mVolumes.remove(volume); 1257b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mVolumesByPath.remove(volume.getPath()); 1258b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mVolumeStates.remove(volume.getPath()); 1259b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1260b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1261b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey private StorageVolume getPrimaryPhysicalVolume() { 1262b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 1263b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey for (StorageVolume volume : mVolumes) { 1264b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (volume.isPrimary() && !volume.isEmulated()) { 1265b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey return volume; 1266b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1267b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1268b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1269b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey return null; 1270b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1271b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1272b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey /** 1273207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Constructs a new MountService instance 1274207e538350665cea00e1aa70b8094beca4a34e45San Mehat * 1275207e538350665cea00e1aa70b8094beca4a34e45San Mehat * @param context Binder context for this service 1276207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 1277207e538350665cea00e1aa70b8094beca4a34e45San Mehat public MountService(Context context) { 1278207e538350665cea00e1aa70b8094beca4a34e45San Mehat mContext = context; 12792f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood 1280b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 1281b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey readStorageListLocked(); 128203559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood } 128303559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood 1284207e538350665cea00e1aa70b8094beca4a34e45San Mehat // XXX: This will go away soon in favor of IMountServiceObserver 1285207e538350665cea00e1aa70b8094beca4a34e45San Mehat mPms = (PackageManagerService) ServiceManager.getService("package"); 1286207e538350665cea00e1aa70b8094beca4a34e45San Mehat 12875f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandlerThread = new HandlerThread("MountService"); 12885f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandlerThread.start(); 12895f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandler = new MountServiceHandler(mHandlerThread.getLooper()); 12905f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler 1291b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // Watch for user changes 1292b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final IntentFilter userFilter = new IntentFilter(); 1293b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey userFilter.addAction(Intent.ACTION_USER_ADDED); 1294b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey userFilter.addAction(Intent.ACTION_USER_REMOVED); 1295b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler); 1296b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1297b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey // Watch for USB changes on primary volume 1298b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume primary = getPrimaryPhysicalVolume(); 1299b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (primary != null && primary.allowMassStorage()) { 1300b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mContext.registerReceiver( 1301b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_STATE), null, mHandler); 1302b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1303b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1304a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Add OBB Action Handler to MountService thread. 1305a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper()); 1306a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1307c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen /* 1308305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * Create the connection to vold with a maximum queue of twice the 1309305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * amount of containers we'd ever expect to have. This keeps an 1310305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * "asec list" from blocking a thread repeatedly. 1311305bcbf0c961840c4505770d084a1caacc074dbbKenny Root */ 1312470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25); 131351a573c76737733638c475f52e441c814e6645ccKenny Root 1314305bcbf0c961840c4505770d084a1caacc074dbbKenny Root Thread thread = new Thread(mConnector, VOLD_TAG); 1315207e538350665cea00e1aa70b8094beca4a34e45San Mehat thread.start(); 1316fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey 131707714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root // Add ourself to the Watchdog monitors if enabled. 131807714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root if (WATCHDOG_ENABLE) { 131907714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root Watchdog.getInstance().addMonitor(this); 132007714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root } 1321207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1322207e538350665cea00e1aa70b8094beca4a34e45San Mehat 1323b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey public void systemReady() { 1324b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mSystemReady = true; 1325b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget(); 1326b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 1327b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1328207e538350665cea00e1aa70b8094beca4a34e45San Mehat /** 13294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Exposed API calls below here 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13317fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 13324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void registerListener(IMountServiceListener listener) { 13334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 13344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = new MountServiceBinderListener(listener); 13354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 13364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat listener.asBinder().linkToDeath(bl, 0); 13374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.add(bl); 13384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 1339a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to link to listener death"); 13404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 13417fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void unregisterListener(IMountServiceListener listener) { 13454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 13464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for(MountServiceBinderListener bl : mListeners) { 13474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (bl.mListener == listener) { 13484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(mListeners.indexOf(bl)); 13495c25a2d338e9609d54e58cc1916c91cd8e9979abVairavan Srinivasan listener.asBinder().unlinkToDeath(bl, 0); 13504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return; 13514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 13524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13566ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu public void shutdown(final IMountShutdownObserver observer) { 13574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.SHUTDOWN); 13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1359a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Shutting down"); 1360b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 13617fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood for (String path : mVolumeStates.keySet()) { 13627fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String state = mVolumeStates.get(path); 13637fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood 13647fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state.equals(Environment.MEDIA_SHARED)) { 13657fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood /* 13667fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * If the media is currently shared, unshare it. 13677fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * XXX: This is still dangerous!. We should not 13687fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * be rebooting at *all* if UMS is enabled, since 13697fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * the UMS host could have dirty FAT cache entries 13707fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * yet to flush. 13717fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood */ 13727fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood setUsbMassStorageEnabled(false); 13737fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } else if (state.equals(Environment.MEDIA_CHECKING)) { 13747fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood /* 13757fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * If the media is being checked, then we need to wait for 13767fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * it to complete before being able to proceed. 13777fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood */ 13787fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood // XXX: @hackbod - Should we disable the ANR timer here? 13797fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood int retries = 30; 13807fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) { 13817fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood try { 13827fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Thread.sleep(1000); 13837fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } catch (InterruptedException iex) { 13847fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.e(TAG, "Interrupted while waiting for media", iex); 13857fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood break; 13867fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 13877fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood state = Environment.getExternalStorageState(); 13887fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 13897fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (retries == 0) { 13907fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.e(TAG, "Timed out waiting for media to check"); 13917fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 13924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 13937fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 13947fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state.equals(Environment.MEDIA_MOUNTED)) { 13957fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood // Post a unmount message. 13967fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood ShutdownCallBack ucb = new ShutdownCallBack(path, observer); 13977fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb)); 13987fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } else if (observer != null) { 13997fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood /* 14007fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * Observer is waiting for onShutDownComplete when we are done. 14017fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * Since nothing will be done send notification directly so shutdown 14027fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood * sequence can continue. 14037fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood */ 14047fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood try { 14057fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood observer.onShutDownComplete(StorageResultCode.OperationSucceeded); 14067fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } catch (RemoteException e) { 14077fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.w(TAG, "RemoteException when shutting down"); 14087fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 14097fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 14105d0db4d356346bee68aec9a124df70dbaa9aaed1Johan Alfven } 14111f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14140eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private boolean getUmsEnabling() { 14150eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu synchronized (mListeners) { 14160eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu return mUmsEnabling; 14170eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 14180eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 14190eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 14200eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private void setUmsEnabling(boolean enable) { 14210eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu synchronized (mListeners) { 1422fc71125104650c61ab5b04f4c943de761d58cba6Tony Wu mUmsEnabling = enable; 14230eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 14240eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 14250eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 1426b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageConnected() { 1427207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 14287fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 14290eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (getUmsEnabling()) { 1430b104340496e3a531e26c8f428c808eca0e039f50San Mehat return true; 1431b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1432ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood synchronized (mListeners) { 1433ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood return mUmsAvailable; 1434ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood } 14354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14370eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu public void setUsbMassStorageEnabled(boolean enable) { 1438207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 14390eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 14400eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 1441b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume primary = getPrimaryPhysicalVolume(); 1442b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (primary == null) return; 1443b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 14440eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // TODO: Add support for multiple share methods 1445b104340496e3a531e26c8f428c808eca0e039f50San Mehat 14460eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 14470eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * If the volume is mounted and we're enabling then unmount it 14480eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 1449b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey String path = primary.getPath(); 14500eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String vs = getVolumeState(path); 14510eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String method = "ums"; 14520eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (enable && vs.equals(Environment.MEDIA_MOUNTED)) { 14530eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Override for isUsbMassStorageEnabled() 14540eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu setUmsEnabling(enable); 14550eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true); 14560eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb)); 14570eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Clear override 14580eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu setUmsEnabling(false); 14590eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 14600eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 14610eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * If we disabled UMS then mount the volume 14620eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 14630eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (!enable) { 14640eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doShareUnshareVolume(path, method, enable); 14650eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (doMountVolume(path) != StorageResultCode.OperationSucceeded) { 1466a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to remount " + path + 14670eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu " after disabling share method " + method); 14680eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 14690eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * Even though the mount failed, the unshare didn't so don't indicate an error. 14700eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * The mountVolume() call will have set the storage state and sent the necessary 14710eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * broadcasts. 14720eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 14730eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 14740eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 14754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1477b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageEnabled() { 1478207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1479b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 1480b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume primary = getPrimaryPhysicalVolume(); 1481b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (primary != null) { 1482b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey return doGetVolumeShared(primary.getPath(), "ums"); 1483b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } else { 1484b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey return false; 1485b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14879ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * @return state of the volume at the specified mount point 14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String getVolumeState(String mountPoint) { 1492b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 14937fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood String state = mVolumeStates.get(mountPoint); 14947fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood if (state == null) { 14957fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume"); 149618db5c5690472f9da6ce2d580067307378675809Ken Sumrall if (SystemProperties.get("vold.encrypt_progress").length() != 0) { 149718db5c5690472f9da6ce2d580067307378675809Ken Sumrall state = Environment.MEDIA_REMOVED; 149818db5c5690472f9da6ce2d580067307378675809Ken Sumrall } else { 149918db5c5690472f9da6ce2d580067307378675809Ken Sumrall throw new IllegalArgumentException(); 150018db5c5690472f9da6ce2d580067307378675809Ken Sumrall } 15017fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 15024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 15037fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood return state; 15047fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood } 15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1507b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey @Override 1508e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root public boolean isExternalStorageEmulated() { 1509b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey return mEmulatedTemplate != null; 1510e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root } 1511e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root 15124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int mountVolume(String path) { 15134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1515207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1516207e538350665cea00e1aa70b8094beca4a34e45San Mehat return doMountVolume(path); 15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 151913c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo public void unmountVolume(String path, boolean force, boolean removeEncryption) { 15204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1521207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15238a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu String volState = getVolumeState(path); 152413c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo if (DEBUG_UNMOUNT) { 152513c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo Slog.i(TAG, "Unmounting " + path 152613c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo + " force = " + force 152713c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo + " removeEncryption = " + removeEncryption); 152813c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo } 15298a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (Environment.MEDIA_UNMOUNTED.equals(volState) || 15308a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_REMOVED.equals(volState) || 15318a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_SHARED.equals(volState) || 15328a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_UNMOUNTABLE.equals(volState)) { 15338a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // Media already unmounted or cannot be unmounted. 15348a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // TODO return valid return code when adding observer call back. 15358a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu return; 15368a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 153713c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo UnmountCallBack ucb = new UnmountCallBack(path, force, removeEncryption); 1538c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb)); 15394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int formatVolume(String path) { 15424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); 1543207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1545207e538350665cea00e1aa70b8094beca4a34e45San Mehat return doFormatVolume(path); 15469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15473697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1548ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood public int[] getStorageUsers(String path) { 1549c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1550c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat waitForReady(); 1551c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat try { 1552dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final String[] r = NativeDaemonEvent.filterMessageList( 1553dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.executeForList("storage", "users", path), 1554dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey VoldResponseCode.StorageUsersListResult); 1555dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey 1556c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat // FMT: <pid> <process name> 1557c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat int[] data = new int[r.length]; 1558c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat for (int i = 0; i < r.length; i++) { 1559dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey String[] tok = r[i].split(" "); 1560c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat try { 1561c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat data[i] = Integer.parseInt(tok[0]); 1562c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } catch (NumberFormatException nfe) { 1563a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Error parsing pid %s", tok[0])); 1564c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return new int[0]; 1565c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1566c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1567c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return data; 1568c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } catch (NativeDaemonConnectorException e) { 1569a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to retrieve storage users list", e); 1570c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return new int[0]; 1571c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1572c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1573c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat 1574b104340496e3a531e26c8f428c808eca0e039f50San Mehat private void warnOnNotMounted() { 1575b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final StorageVolume primary = getPrimaryPhysicalVolume(); 157632ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey if (primary != null) { 157732ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey boolean mounted = false; 157832ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey try { 157932ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey mounted = Environment.MEDIA_MOUNTED.equals(getVolumeState(primary.getPath())); 158032ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey } catch (IllegalStateException e) { 158132ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey } 158232ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey 158332ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey if (!mounted) { 158432ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey Slog.w(TAG, "getSecureContainerList() called when storage not mounted"); 158532ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey } 1586b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1587b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1588b104340496e3a531e26c8f428c808eca0e039f50San Mehat 15894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String[] getSecureContainerList() { 15904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 1591207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1592b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1593f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 15944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1595dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return NativeDaemonEvent.filterMessageList( 1596dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult); 15974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 15984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return new String[0]; 159902735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 16003697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 16013697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 16026dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root public int createSecureContainer(String id, int sizeMb, String fstype, String key, 16036dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root int ownerUid, boolean external) { 16044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_CREATE); 1605207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1606b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 16074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1608b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 16094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 16106dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root mConnector.execute("asec", "create", id, sizeMb, fstype, key, ownerUid, 16116dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root external ? "1" : "0"); 16124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1613b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 161402735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1615a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1616a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (rc == StorageResultCode.OperationSucceeded) { 1617a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1618a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat mAsecMountSet.add(id); 1619a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1620a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 16214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 16223697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 16233697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 16244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int finalizeSecureContainer(String id) { 16254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_CREATE); 1626b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 16274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1628b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 16294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1630dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("asec", "finalize", id); 1631a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat /* 1632a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat * Finalization does a remount, so no need 1633a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat * to update mAsecMountSet 1634a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat */ 16356dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root } catch (NativeDaemonConnectorException e) { 16366dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root rc = StorageResultCode.OperationFailedInternalError; 16376dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root } 16386dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root return rc; 16396dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root } 16406dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root 16416dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root public int fixPermissionsSecureContainer(String id, int gid, String filename) { 16426dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root validatePermission(android.Manifest.permission.ASEC_CREATE); 16436dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root warnOnNotMounted(); 16446dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root 16456dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root int rc = StorageResultCode.OperationSucceeded; 16466dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root try { 16476dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root mConnector.execute("asec", "fixperms", id, gid, filename); 16486dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root /* 16496dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root * Fix permissions does a remount, so no need to update 16506dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root * mAsecMountSet 16516dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root */ 16524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1653b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 165402735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 16554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 16563697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 16573697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1658d970998b0d489774ad1c5b94b47d233912f00214San Mehat public int destroySecureContainer(String id, boolean force) { 16594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_DESTROY); 1660207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1661b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1662f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 1663aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 1664aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 1665aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 1666aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 1667aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 1668aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 1669aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 1670aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 1671b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 16724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1673dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final Command cmd = new Command("asec", "destroy", id); 1674dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey if (force) { 1675dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey cmd.appendArg("force"); 1676dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } 1677dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute(cmd); 16784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1679d970998b0d489774ad1c5b94b47d233912f00214San Mehat int code = e.getCode(); 1680d970998b0d489774ad1c5b94b47d233912f00214San Mehat if (code == VoldResponseCode.OpFailedStorageBusy) { 1681d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedStorageBusy; 1682d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else { 1683d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedInternalError; 1684d970998b0d489774ad1c5b94b47d233912f00214San Mehat } 168502735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1686a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1687a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (rc == StorageResultCode.OperationSucceeded) { 1688a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1689a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (mAsecMountSet.contains(id)) { 1690a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat mAsecMountSet.remove(id); 1691a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1692a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1693a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1694a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 16954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 16963697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 16979ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 16984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int mountSecureContainer(String id, String key, int ownerUid) { 16994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 1700207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1701b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 17024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1703a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1704a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (mAsecMountSet.contains(id)) { 1705a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageMounted; 1706a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1707a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1708a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1709b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 17104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1711dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("asec", "mount", id, key, ownerUid); 17124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1713f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root int code = e.getCode(); 1714f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root if (code != VoldResponseCode.OpFailedStorageBusy) { 1715f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root rc = StorageResultCode.OperationFailedInternalError; 1716f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root } 171702735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 17186cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 17196cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (rc == StorageResultCode.OperationSucceeded) { 17206cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 17216cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat mAsecMountSet.add(id); 17226cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 17236cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 17244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 17253697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 17263697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1727d970998b0d489774ad1c5b94b47d233912f00214San Mehat public int unmountSecureContainer(String id, boolean force) { 17284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 1729207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1730b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 17314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 17326cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 17336cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (!mAsecMountSet.contains(id)) { 1734a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageNotMounted; 17356cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 17366cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 17376cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 1738aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 1739aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 1740aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 1741aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 1742aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 1743aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 1744aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 1745aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 1746b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 17474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1748dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final Command cmd = new Command("asec", "unmount", id); 1749dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey if (force) { 1750dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey cmd.appendArg("force"); 1751dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } 1752dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute(cmd); 17534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1754d970998b0d489774ad1c5b94b47d233912f00214San Mehat int code = e.getCode(); 1755d970998b0d489774ad1c5b94b47d233912f00214San Mehat if (code == VoldResponseCode.OpFailedStorageBusy) { 1756d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedStorageBusy; 1757d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else { 1758d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedInternalError; 1759d970998b0d489774ad1c5b94b47d233912f00214San Mehat } 176002735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 17616cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 17626cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (rc == StorageResultCode.OperationSucceeded) { 17636cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 17646cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat mAsecMountSet.remove(id); 17656cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 17666cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 17674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 17689dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat } 17699dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat 17706cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat public boolean isSecureContainerMounted(String id) { 17716cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 17726cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat waitForReady(); 17736cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat warnOnNotMounted(); 17746cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 17756cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 17766cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat return mAsecMountSet.contains(id); 17776cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 17786cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 17796cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 17804270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int renameSecureContainer(String oldId, String newId) { 17814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_RENAME); 1782207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1783b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 17844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1785a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 178685451ee15fdf6cae371dc3005441988c7d426401San Mehat /* 17879ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks * Because a mounted container has active internal state which cannot be 178885451ee15fdf6cae371dc3005441988c7d426401San Mehat * changed while active, we must ensure both ids are not currently mounted. 178985451ee15fdf6cae371dc3005441988c7d426401San Mehat */ 179085451ee15fdf6cae371dc3005441988c7d426401San Mehat if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) { 1791a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageMounted; 1792a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1793a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1794a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1795b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 17964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1797dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("asec", "rename", oldId, newId); 17984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1799b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 180002735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1801a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 18024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 180345f61040823d8c442838f75cde8760f236603daeSan Mehat } 180445f61040823d8c442838f75cde8760f236603daeSan Mehat 18054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String getSecureContainerPath(String id) { 18064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 1807207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1808b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1809f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 1810dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 18112d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat try { 1812dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("asec", "path", id); 1813dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event.checkCode(VoldResponseCode.AsecPathResult); 1814dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return event.getMessage(); 18152d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat } catch (NativeDaemonConnectorException e) { 18162d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat int code = e.getCode(); 18172d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat if (code == VoldResponseCode.OpFailedStorageNotFound) { 1818a20c8ef471666cf8b0dca91a8739ff18af1741a5Fredrik Helmer Slog.i(TAG, String.format("Container '%s' not found", id)); 1819a20c8ef471666cf8b0dca91a8739ff18af1741a5Fredrik Helmer return null; 182022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else { 18212d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat throw new IllegalStateException(String.format("Unexpected response code %d", code)); 182222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 182322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 182422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 1825292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn 1826292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn public String getSecureContainerFilesystemPath(String id) { 1827292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn validatePermission(android.Manifest.permission.ASEC_ACCESS); 1828292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn waitForReady(); 1829292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn warnOnNotMounted(); 1830292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn 1831dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 1832292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn try { 1833dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("asec", "fspath", id); 1834dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event.checkCode(VoldResponseCode.AsecPathResult); 1835dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return event.getMessage(); 1836292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn } catch (NativeDaemonConnectorException e) { 1837292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn int code = e.getCode(); 1838292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn if (code == VoldResponseCode.OpFailedStorageNotFound) { 1839292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn Slog.i(TAG, String.format("Container '%s' not found", id)); 1840292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn return null; 1841292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn } else { 1842292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn throw new IllegalStateException(String.format("Unexpected response code %d", code)); 1843292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn } 1844292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn } 1845292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn } 1846e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu 1847e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu public void finishMediaUpdate() { 1848e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE); 1849e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu } 185002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1851a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) { 1852a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (callerUid == android.os.Process.SYSTEM_UID) { 1853a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return true; 1854a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1855a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 185602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (packageName == null) { 185702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return false; 185802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 185902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1860f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn final int packageUid = mPms.getPackageUid(packageName, UserHandle.getUserId(callerUid)); 186102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 186202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (DEBUG_OBB) { 186302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root Slog.d(TAG, "packageName = " + packageName + ", packageUid = " + 186402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root packageUid + ", callerUid = " + callerUid); 186502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 186602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 186702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return callerUid == packageUid; 186802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 186902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 18704fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey public String getMountedObbPath(String rawPath) { 18714fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 1872af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 187302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root waitForReady(); 187402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root warnOnNotMounted(); 187502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 18764fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final ObbState state; 18774fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey synchronized (mObbPathToStateMap) { 18784fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey state = mObbPathToStateMap.get(rawPath); 18794fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 18804fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (state == null) { 18814fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Slog.w(TAG, "Failed to find OBB mounted at " + rawPath); 18824fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return null; 18834fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 18844fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 1885dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 188602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root try { 18874fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey event = mConnector.execute("obb", "path", state.voldPath); 1888dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event.checkCode(VoldResponseCode.AsecPathResult); 1889dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return event.getMessage(); 189002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } catch (NativeDaemonConnectorException e) { 189102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root int code = e.getCode(); 189202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (code == VoldResponseCode.OpFailedStorageNotFound) { 1893a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return null; 189402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } else { 189502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root throw new IllegalStateException(String.format("Unexpected response code %d", code)); 189602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 189702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 189802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 189902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 19004fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey @Override 19014fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey public boolean isObbMounted(String rawPath) { 19024fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 1903a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root synchronized (mObbMounts) { 19044fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return mObbPathToStateMap.containsKey(rawPath); 1905a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1906a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1907a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 19084fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey @Override 19094fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey public void mountObb( 19104fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) { 19114fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 19124fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null"); 19134fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(token, "token cannot be null"); 19144fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 19154fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final int callingUid = Binder.getCallingUid(); 19164fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce); 19174fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final ObbAction action = new MountObbAction(obbState, key, callingUid); 1918a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 1919a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1920a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1921a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Send to OBB handler: " + action.toString()); 192202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 192302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 19244fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey @Override 19254fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) { 19264fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Preconditions.checkNotNull(rawPath, "rawPath cannot be null"); 19274fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 19284fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final ObbState existingState; 19294fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey synchronized (mObbPathToStateMap) { 19304fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey existingState = mObbPathToStateMap.get(rawPath); 1931f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root } 1932f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root 19334fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (existingState != null) { 19344fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey // TODO: separate state object from request data 19354fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final int callingUid = Binder.getCallingUid(); 19364fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final ObbState newState = new ObbState( 19374fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey rawPath, existingState.canonicalPath, callingUid, token, nonce); 19384fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final ObbAction action = new UnmountObbAction(newState, force); 19394fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 1940a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 19414fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (DEBUG_OBB) 19424fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Slog.i(TAG, "Send to OBB handler: " + action.toString()); 19434fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } else { 19444fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Slog.w(TAG, "Unknown OBB mount at " + rawPath); 19454fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 1946a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 194702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1948444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo @Override 1949444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo public int getEncryptionState() { 1950444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 1951444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo "no permission to access the crypt keeper"); 1952444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo 1953444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo waitForReady(); 1954444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo 1955dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 1956444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo try { 1957dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("cryptfs", "cryptocomplete"); 1958dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return Integer.parseInt(event.getMessage()); 1959444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo } catch (NumberFormatException e) { 1960444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo // Bad result - unexpected. 1961444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete"); 1962444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo return ENCRYPTION_STATE_ERROR_UNKNOWN; 1963444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo } catch (NativeDaemonConnectorException e) { 1964444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo // Something bad happened. 1965444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo Slog.w(TAG, "Error in communicating with cryptfs in validating"); 1966444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo return ENCRYPTION_STATE_ERROR_UNKNOWN; 1967444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo } 1968444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo } 1969444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo 1970444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo @Override 19715af0b916f850486cff4797355bf9e7dc3352fe00Jason parks public int decryptStorage(String password) { 1972f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (TextUtils.isEmpty(password)) { 1973f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks throw new IllegalArgumentException("password cannot be empty"); 19745af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 19755af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 19768888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 19778888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks "no permission to access the crypt keeper"); 19785af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 19795af0b916f850486cff4797355bf9e7dc3352fe00Jason parks waitForReady(); 19805af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 19815af0b916f850486cff4797355bf9e7dc3352fe00Jason parks if (DEBUG_EVENTS) { 19825af0b916f850486cff4797355bf9e7dc3352fe00Jason parks Slog.i(TAG, "decrypting storage..."); 19835af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 19845af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 1985dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 19865af0b916f850486cff4797355bf9e7dc3352fe00Jason parks try { 1987dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("cryptfs", "checkpw", password); 19889ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 1989da6aedf716bfdd40148823fb63d666d34b7b425eFredrik Roubert final int code = Integer.parseInt(event.getMessage()); 19909ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks if (code == 0) { 19919ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks // Decrypt was successful. Post a delayed message before restarting in order 19929ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks // to let the UI to clear itself 19939ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks mHandler.postDelayed(new Runnable() { 19949ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks public void run() { 199531c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey try { 1996dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("cryptfs", "restart"); 199731c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey } catch (NativeDaemonConnectorException e) { 199831c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey Slog.e(TAG, "problem executing in background", e); 199931c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey } 20009ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks } 2001f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks }, 1000); // 1 second 20029ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks } 20039ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 20049ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks return code; 20055af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } catch (NativeDaemonConnectorException e) { 20065af0b916f850486cff4797355bf9e7dc3352fe00Jason parks // Decryption failed 20075af0b916f850486cff4797355bf9e7dc3352fe00Jason parks return e.getCode(); 20085af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 20095af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 20105af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 201156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks public int encryptStorage(String password) { 2012f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (TextUtils.isEmpty(password)) { 2013f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks throw new IllegalArgumentException("password cannot be empty"); 201456aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 201556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 20168888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 20178888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks "no permission to access the crypt keeper"); 201856aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 201956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks waitForReady(); 202056aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 202156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks if (DEBUG_EVENTS) { 20228888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks Slog.i(TAG, "encrypting storage..."); 202356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 202456aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 202556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks try { 2026dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute("cryptfs", "enablecrypto", "inplace", password); 202756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } catch (NativeDaemonConnectorException e) { 202856aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks // Encryption failed 202956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks return e.getCode(); 203056aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 203156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 203256aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks return 0; 203356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 203456aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 2035f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks public int changeEncryptionPassword(String password) { 2036f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (TextUtils.isEmpty(password)) { 2037f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks throw new IllegalArgumentException("password cannot be empty"); 2038f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 2039f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 2040f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 2041f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks "no permission to access the crypt keeper"); 2042f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 2043f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks waitForReady(); 2044f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 2045f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (DEBUG_EVENTS) { 2046f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks Slog.i(TAG, "changing encryption password..."); 2047f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 2048f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 2049dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 2050f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks try { 2051dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("cryptfs", "changepw", password); 2052dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return Integer.parseInt(event.getMessage()); 2053f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } catch (NativeDaemonConnectorException e) { 2054f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks // Encryption failed 2055f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks return e.getCode(); 2056f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 2057f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 2058f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 205932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate /** 206032418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate * Validate a user-supplied password string with cryptfs 206132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate */ 206232418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate @Override 206332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate public int verifyEncryptionPassword(String password) throws RemoteException { 206432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate // Only the system process is permitted to validate passwords 206532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { 206632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate throw new SecurityException("no permission to access the crypt keeper"); 206732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } 206832418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 206932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 207032418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate "no permission to access the crypt keeper"); 207132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 207232418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate if (TextUtils.isEmpty(password)) { 207332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate throw new IllegalArgumentException("password cannot be empty"); 207432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } 207532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 207632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate waitForReady(); 207732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 207832418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate if (DEBUG_EVENTS) { 207932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate Slog.i(TAG, "validating encryption password..."); 208032418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } 208132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 2082dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey final NativeDaemonEvent event; 208332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate try { 2084dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey event = mConnector.execute("cryptfs", "verifypw", password); 2085dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey Slog.i(TAG, "cryptfs verifypw => " + event.getMessage()); 2086dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey return Integer.parseInt(event.getMessage()); 208732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } catch (NativeDaemonConnectorException e) { 208832418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate // Encryption failed 208932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate return e.getCode(); 209032418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } 209132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate } 209232418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate 2093b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey @Override 2094b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey public StorageVolume[] getVolumeList() { 2095b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final int callingUserId = UserHandle.getCallingUserId(); 2096b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final boolean accessAll = (mContext.checkPermission( 2097b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey android.Manifest.permission.ACCESS_ALL_EXTERNAL_STORAGE, 2098b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey Binder.getCallingPid(), Binder.getCallingUid()) == PERMISSION_GRANTED); 2099b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey 2100b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 2101b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final ArrayList<StorageVolume> filtered = Lists.newArrayList(); 2102b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey for (StorageVolume volume : mVolumes) { 2103b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final UserHandle owner = volume.getOwner(); 2104b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey final boolean ownerMatch = owner == null || owner.getIdentifier() == callingUserId; 2105b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey if (accessAll || ownerMatch) { 2106b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey filtered.add(volume); 2107b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey } 21088fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood } 2109b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey return filtered.toArray(new StorageVolume[filtered.size()]); 21108fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood } 21118fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood } 21128fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood 2113af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private void addObbStateLocked(ObbState obbState) throws RemoteException { 2114af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IBinder binder = obbState.getBinder(); 2115af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root List<ObbState> obbStates = mObbMounts.get(binder); 21165919ac6b4188285324646772501ef4b97b353cf4Kenny Root 2117af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates == null) { 2118af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates = new ArrayList<ObbState>(); 2119af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.put(binder, obbStates); 2120af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 2121af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root for (final ObbState o : obbStates) { 21224fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (o.rawPath.equals(obbState.rawPath)) { 2123af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalStateException("Attempt to add ObbState twice. " 2124af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + "This indicates an error in the MountService logic."); 21255919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 21265919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 212702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 212802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2129af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates.add(obbState); 2130af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 2131af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState.link(); 2132af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (RemoteException e) { 2133af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root /* 2134af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * The binder died before we could link it, so clean up our state 2135af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * and return failure. 2136af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root */ 2137af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates.remove(obbState); 2138af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.isEmpty()) { 2139af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.remove(binder); 214005105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 21415919ac6b4188285324646772501ef4b97b353cf4Kenny Root 2142af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Rethrow the error so mountObb can get it 2143af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw e; 214402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 2145af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 21464fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey mObbPathToStateMap.put(obbState.rawPath, obbState); 2147a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 214802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2149af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private void removeObbStateLocked(ObbState obbState) { 2150af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IBinder binder = obbState.getBinder(); 2151af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStates = mObbMounts.get(binder); 2152af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates != null) { 2153af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.remove(obbState)) { 2154af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState.unlink(); 2155af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2156af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.isEmpty()) { 2157af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.remove(binder); 2158af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 215938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2160af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 21614fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey mObbPathToStateMap.remove(obbState.rawPath); 216238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 216338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2164a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private class ObbActionHandler extends Handler { 2165a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean mBound = false; 2166480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root private final List<ObbAction> mActions = new LinkedList<ObbAction>(); 2167a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2168a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbActionHandler(Looper l) { 2169a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(l); 2170a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2171a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2172a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 2173a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleMessage(Message msg) { 2174a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root switch (msg.what) { 2175a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_RUN_ACTION: { 2176480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root final ObbAction action = (ObbAction) msg.obj; 2177a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2178a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2179a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString()); 2180a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2181a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // If a bind was already initiated we don't really 2182a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // need to do anything. The pending install 2183a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // will be processed later on. 2184a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!mBound) { 2185a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // If this is the only one pending we might 2186a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // have to bind to the service again. 2187a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!connectToService()) { 2188a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Failed to bind to media container service"); 2189a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 2190a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return; 2191a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2192a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2193735de3b38abbd6564082a819377673ee593744a6Kenny Root 2194735de3b38abbd6564082a819377673ee593744a6Kenny Root mActions.add(action); 2195a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 2196a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2197a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_BOUND: { 2198a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2199a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_BOUND"); 2200a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (msg.obj != null) { 2201a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContainerService = (IMediaContainerService) msg.obj; 2202a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2203a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mContainerService == null) { 2204a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Something seriously wrong. Bail out 2205a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Cannot bind to media container service"); 2206a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root for (ObbAction action : mActions) { 2207a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Indicate service bind error 2208a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 2209a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2210a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.clear(); 2211a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else if (mActions.size() > 0) { 2212480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root final ObbAction action = mActions.get(0); 2213a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (action != null) { 2214a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.execute(this); 2215a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2216a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 2217a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Should never happen ideally. 2218a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.w(TAG, "Empty queue"); 2219a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2220a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 2221a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2222a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_RECONNECT: { 2223a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2224a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_RECONNECT"); 2225a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() > 0) { 2226a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mBound) { 2227a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root disconnectService(); 2228a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2229a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!connectToService()) { 2230a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Failed to bind to media container service"); 2231a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root for (ObbAction action : mActions) { 2232a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Indicate service bind error 2233a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 2234a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2235a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.clear(); 2236a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2237a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2238a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 2239a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2240a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_UNBIND: { 2241a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2242a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_UNBIND"); 2243a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2244a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Delete pending install 2245a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() > 0) { 2246a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.remove(0); 2247a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2248a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() == 0) { 2249a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mBound) { 2250a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root disconnectService(); 2251a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2252a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 2253a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // There are more pending requests in queue. 2254a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Just post MCS_BOUND message to trigger processing 2255a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // of next pending install. 2256a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND); 2257a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2258a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 2259a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2260af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root case OBB_FLUSH_MOUNT_STATE: { 2261af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final String path = (String) msg.obj; 2262af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2263af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 2264af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.i(TAG, "Flushing all OBB state for path " + path); 2265af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2266af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 2267af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>(); 2268af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 22694fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final Iterator<ObbState> i = mObbPathToStateMap.values().iterator(); 2270af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (i.hasNext()) { 22714fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final ObbState state = i.next(); 2272af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2273af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root /* 2274af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * If this entry's source file is in the volume path 2275af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * that got unmounted, remove it because it's no 2276af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * longer valid. 2277af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root */ 22784fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (state.canonicalPath.startsWith(path)) { 22794fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey obbStatesToRemove.add(state); 2280af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2281af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2282af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2283af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root for (final ObbState obbState : obbStatesToRemove) { 2284af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 22854fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Slog.i(TAG, "Removing state for " + obbState.rawPath); 2286af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2287af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root removeObbStateLocked(obbState); 2288af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2289af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 22904fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey obbState.token.onObbResult(obbState.rawPath, obbState.nonce, 2291af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root OnObbStateChangeListener.UNMOUNTED); 2292af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (RemoteException e) { 2293af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.i(TAG, "Couldn't send unmount notification for OBB: " 22944fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey + obbState.rawPath); 2295af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2296af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2297af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2298af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root break; 2299af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 230002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 230102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 230202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2303a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean connectToService() { 2304a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2305a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Trying to bind to DefaultContainerService"); 2306a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2307a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); 2308a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) { 2309a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mBound = true; 2310a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return true; 231102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 2312a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return false; 2313a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2314a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2315a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private void disconnectService() { 2316a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContainerService = null; 2317a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mBound = false; 2318a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContext.unbindService(mDefContainerConn); 231902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 232002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 232102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2322a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root abstract class ObbAction { 2323a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int MAX_RETRIES = 3; 2324a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private int mRetries; 232502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2326a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbState mObbState; 2327a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2328a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbAction(ObbState obbState) { 2329a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbState = obbState; 233002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 233102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 2332a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void execute(ObbActionHandler handler) { 2333a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root try { 2334a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2335444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo Slog.i(TAG, "Starting to execute action: " + toString()); 2336a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mRetries++; 2337a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mRetries > MAX_RETRIES) { 2338a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); 2339480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 2340a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleError(); 2341a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return; 2342a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 2343a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleExecute(); 2344a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2345a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Posting install MCS_UNBIND"); 2346a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 2347a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2348a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } catch (RemoteException e) { 2349a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2350a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Posting install MCS_RECONNECT"); 2351a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT); 2352a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } catch (Exception e) { 2353a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 2354a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.d(TAG, "Error handling OBB action", e); 2355a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleError(); 235617eb6fb07cc6965f09c51adc70b3c291f57a784aKenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 235702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 2358a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 235902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 236005105f7abe02b2dff91d6260b3628c8b97816babKenny Root abstract void handleExecute() throws RemoteException, IOException; 2361a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root abstract void handleError(); 236238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 236338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root protected ObbInfo getObbInfo() throws IOException { 236438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root ObbInfo obbInfo; 236538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root try { 23664fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey obbInfo = mContainerService.getObbInfo(mObbState.ownerPath); 236738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } catch (RemoteException e) { 236838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for " 23694fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey + mObbState.ownerPath); 237038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root obbInfo = null; 237138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 237238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root if (obbInfo == null) { 23734fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey throw new IOException("Couldn't read OBB file: " + mObbState.ownerPath); 237438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 237538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return obbInfo; 237638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 237738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2378af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root protected void sendNewStatusOrIgnore(int status) { 2379af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (mObbState == null || mObbState.token == null) { 2380af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2381af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2382af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 238338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root try { 23844fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status); 238538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } catch (RemoteException e) { 238638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged"); 238738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 238838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2389a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2390a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2391a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class MountObbAction extends ObbAction { 2392444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo private final String mKey; 23934fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey private final int mCallingUid; 2394a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 23954fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey MountObbAction(ObbState obbState, String key, int callingUid) { 2396a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(obbState); 2397a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mKey = key; 23984fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey mCallingUid = callingUid; 2399a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2400a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 24015af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 2402735de3b38abbd6564082a819377673ee593744a6Kenny Root public void handleExecute() throws IOException, RemoteException { 2403af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root waitForReady(); 2404af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root warnOnNotMounted(); 2405af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 240638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root final ObbInfo obbInfo = getObbInfo(); 240738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 24084fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) { 2409af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename 2410af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + " which is owned by " + obbInfo.packageName); 2411af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); 2412af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2413af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2414af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2415af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final boolean isMounted; 2416af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 24174fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath); 2418af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2419af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (isMounted) { 2420af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename); 2421af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED); 2422af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2423af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2424af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2425af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final String hashedKey; 2426af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (mKey == null) { 2427af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root hashedKey = "none"; 2428af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 2429af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 24303b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 24313b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 24323b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt, 24333b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE); 24343b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root SecretKey key = factory.generateSecret(ks); 24353b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root BigInteger bi = new BigInteger(key.getEncoded()); 24363b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root hashedKey = bi.toString(16); 2437af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NoSuchAlgorithmException e) { 24383b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root Slog.e(TAG, "Could not load PBKDF2 algorithm", e); 24393b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 24403b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root return; 24413b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root } catch (InvalidKeySpecException e) { 24423b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e); 24433b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 2444af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 244538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2446a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2447a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2448af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int rc = StorageResultCode.OperationSucceeded; 2449af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 2450dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute( 24514fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey "obb", "mount", mObbState.voldPath, hashedKey, mObbState.ownerGid); 2452af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NativeDaemonConnectorException e) { 2453af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int code = e.getCode(); 2454af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (code != VoldResponseCode.OpFailedStorageBusy) { 2455af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedInternalError; 2456a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2457af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2458a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2459af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (rc == StorageResultCode.OperationSucceeded) { 2460af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 24614fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Slog.d(TAG, "Successfully mounted OBB " + mObbState.voldPath); 246238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2463af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 2464af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root addObbStateLocked(mObbState); 2465a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 246638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2467af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED); 246802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } else { 246905105f7abe02b2dff91d6260b3628c8b97816babKenny Root Slog.e(TAG, "Couldn't mount OBB file: " + rc); 2470a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2471af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT); 247202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 247302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 247402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 24755af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 2476a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleError() { 2477af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 247802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 2479a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2480a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 2481a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public String toString() { 2482a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root StringBuilder sb = new StringBuilder(); 2483a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("MountObbAction{"); 24844fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append(mObbState); 2485a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append('}'); 2486a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return sb.toString(); 2487a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2488a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2489a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2490a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class UnmountObbAction extends ObbAction { 2491444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo private final boolean mForceUnmount; 2492a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2493a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root UnmountObbAction(ObbState obbState, boolean force) { 2494a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(obbState); 2495a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mForceUnmount = force; 2496a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2497a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 24985af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 249938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root public void handleExecute() throws IOException { 2500af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root waitForReady(); 2501af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root warnOnNotMounted(); 2502af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 250338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root final ObbInfo obbInfo = getObbInfo(); 2504a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 25054fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final ObbState existingState; 250638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root synchronized (mObbMounts) { 25074fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey existingState = mObbPathToStateMap.get(mObbState.rawPath); 2508af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 250938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 25104fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (existingState == null) { 2511af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED); 2512af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2513a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2514a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 25154fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (existingState.ownerGid != mObbState.ownerGid) { 25164fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath 25174fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey + " (owned by GID " + existingState.ownerGid + ")"); 2518af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); 2519af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2520af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2521a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2522af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int rc = StorageResultCode.OperationSucceeded; 2523af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 25244fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final Command cmd = new Command("obb", "unmount", mObbState.voldPath); 2525dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey if (mForceUnmount) { 2526dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey cmd.appendArg("force"); 2527dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey } 2528dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey mConnector.execute(cmd); 2529af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NativeDaemonConnectorException e) { 2530af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int code = e.getCode(); 2531af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (code == VoldResponseCode.OpFailedStorageBusy) { 2532af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedStorageBusy; 2533af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else if (code == VoldResponseCode.OpFailedStorageNotFound) { 2534af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // If it's not mounted then we've already won. 2535af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationSucceeded; 2536af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 2537af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedInternalError; 2538a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2539a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 254038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2541af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (rc == StorageResultCode.OperationSucceeded) { 2542af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 25434fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey removeObbStateLocked(existingState); 2544af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 254538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2546af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED); 254738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } else { 25484fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey Slog.w(TAG, "Could not unmount OBB: " + existingState); 2549af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT); 255038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2551a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2552a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 25535af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 2554a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleError() { 2555af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 2556a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2557a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2558a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 2559a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public String toString() { 2560a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root StringBuilder sb = new StringBuilder(); 2561a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("UnmountObbAction{"); 25624fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey sb.append(mObbState); 2563a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",force="); 2564a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mForceUnmount); 2565a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append('}'); 2566a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return sb.toString(); 2567a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 256802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 256938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 25708b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey @VisibleForTesting 25714fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey public static String buildObbPath(final String canonicalPath, int userId, boolean forVold) { 25724fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey // TODO: allow caller to provide Environment for full testing 25734fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 25744fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey // Only adjust paths when storage is emulated 25754fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (!Environment.isExternalStorageEmulated()) { 25764fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return canonicalPath; 25774fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 25784fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 25794fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey String path = canonicalPath.toString(); 25804fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 25814fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey // First trim off any external storage prefix 25824fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final UserEnvironment userEnv = new UserEnvironment(userId); 25834fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 25844fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey // /storage/emulated/0 25854fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final String externalPath = userEnv.getExternalStorageDirectory().toString(); 25864fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey // /storage/emulated_legacy 25874fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final String legacyExternalPath = Environment.getLegacyExternalStorageDirectory() 25884fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey .toString(); 25894fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 25904fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (path.startsWith(externalPath)) { 25914fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey path = path.substring(externalPath.length() + 1); 25924fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } else if (path.startsWith(legacyExternalPath)) { 25934fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey path = path.substring(legacyExternalPath.length() + 1); 25944fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } else { 25954fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return canonicalPath; 25964fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 25974fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 25984fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey // Handle special OBB paths on emulated storage 25994fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final String obbPath = "Android/obb"; 26004fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (path.startsWith(obbPath)) { 26014fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey path = path.substring(obbPath.length() + 1); 26024fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 26034fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (forVold) { 26044fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return new File(Environment.getEmulatedStorageObbSource(), path).toString(); 26054fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } else { 26064fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey final UserEnvironment ownerEnv = new UserEnvironment(UserHandle.USER_OWNER); 26074fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return new File(ownerEnv.getExternalStorageObbDirectory(), path).toString(); 26084fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 26094fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 26104fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 26114fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey // Handle normal external storage paths 26124fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey if (forVold) { 26134fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return new File(Environment.getEmulatedStorageSource(userId), path).toString(); 26144fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } else { 26154fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey return new File(userEnv.getExternalStorageDirectory(), path).toString(); 26164fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 26174fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey } 26184fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey 261938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root @Override 262038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 262138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { 262238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root pw.println("Permission Denial: can't dump ActivityManager from from pid=" 262338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() 262438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root + " without permission " + android.Manifest.permission.DUMP); 262538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return; 262638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 262738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 262838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root synchronized (mObbMounts) { 2629af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(" mObbMounts:"); 263038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2631af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet().iterator(); 2632af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (binders.hasNext()) { 2633af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Entry<IBinder, List<ObbState>> e = binders.next(); 2634af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" Key="); pw.println(e.getKey().toString()); 2635af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStates = e.getValue(); 263638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root for (final ObbState obbState : obbStates) { 2637af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" "); pw.println(obbState.toString()); 263838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 263938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2640af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2641af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(""); 2642af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(" mObbPathToStateMap:"); 2643af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator(); 2644af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (maps.hasNext()) { 2645af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Entry<String, ObbState> e = maps.next(); 2646af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" "); pw.print(e.getKey()); 2647af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" -> "); pw.println(e.getValue().toString()); 2648af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 264938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 26504161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root 26514161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root pw.println(""); 26524161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root 2653b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey synchronized (mVolumesLock) { 26544161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root pw.println(" mVolumes:"); 26554161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root 26564161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root final int N = mVolumes.size(); 26574161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root for (int i = 0; i < N; i++) { 26584161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root final StorageVolume v = mVolumes.get(i); 26594161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root pw.print(" "); 26604161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root pw.println(v.toString()); 26614161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root } 26624161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root } 2663470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt 2664470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt pw.println(); 2665470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt pw.println(" mConnection:"); 2666470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt mConnector.dump(fd, pw, args); 266738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 26689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2669fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey /** {@inheritDoc} */ 2670fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey public void monitor() { 2671fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey if (mConnector != null) { 2672fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey mConnector.monitor(); 2673fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey } 2674fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey } 2675fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey} 2676