MountService.java revision 3b1abba6bbc895d63da3e82e9b158c01bd12eddd
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.server; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport com.android.internal.app.IMediaContainerService; 20c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport com.android.server.am.ActivityManagerService; 21c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 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; 2902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.content.res.ObbInfo; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri; 3102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.os.Binder; 32a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.Environment; 33c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Handler; 345f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.HandlerThread; 35a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.IBinder; 365f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.Looper; 37c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Message; 384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehatimport android.os.RemoteException; 39fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapuimport android.os.ServiceManager; 40207e538350665cea00e1aa70b8094beca4a34e45San Mehatimport android.os.SystemClock; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties; 42a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountService; 43a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountServiceListener; 44a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountShutdownObserver; 45a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IObbActionListener; 46af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Rootimport android.os.storage.OnObbStateChangeListener; 47a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.StorageResultCode; 48a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehatimport android.util.Slog; 49a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 5038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.FileDescriptor; 5105105f7abe02b2dff91d6260b3628c8b97816babKenny Rootimport java.io.IOException; 5238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.PrintWriter; 533b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.math.BigInteger; 54735de3b38abbd6564082a819377673ee593744a6Kenny Rootimport java.security.NoSuchAlgorithmException; 553b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.InvalidKeySpecException; 563b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.KeySpec; 5722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehatimport java.util.ArrayList; 58a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.HashMap; 596cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehatimport java.util.HashSet; 6038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Iterator; 61a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.LinkedList; 62a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.List; 63a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.Map; 6438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Map.Entry; 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 663b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKey; 673b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKeyFactory; 683b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.spec.PBEKeySpec; 693b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 71b104340496e3a531e26c8f428c808eca0e039f50San Mehat * MountService implements back-end services for platform storage 72b104340496e3a531e26c8f428c808eca0e039f50San Mehat * management. 73b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @hide - Applications should use android.os.storage.StorageManager 74b104340496e3a531e26c8f428c808eca0e039f50San Mehat * to access the MountService. 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehatclass MountService extends IMountService.Stub 7722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat implements INativeDaemonConnectorCallbacks { 78b104340496e3a531e26c8f428c808eca0e039f50San Mehat private static final boolean LOCAL_LOGD = false; 798a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu private static final boolean DEBUG_UNMOUNT = false; 808a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu private static final boolean DEBUG_EVENTS = false; 8102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root private static final boolean DEBUG_OBB = true; 8202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String TAG = "MountService"; 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 85305bcbf0c961840c4505770d084a1caacc074dbbKenny Root private static final String VOLD_TAG = "VoldConnector"; 86305bcbf0c961840c4505770d084a1caacc074dbbKenny Root 874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Internal vold volume state constants 894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 907fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat class VolumeState { 917fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Init = -1; 927fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int NoMedia = 0; 937fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Idle = 1; 947fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Pending = 2; 957fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Checking = 3; 967fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Mounted = 4; 977fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Unmounting = 5; 987fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Formatting = 6; 997fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Shared = 7; 1007fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int SharedMnt = 8; 1017fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 1027fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 1034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Internal vold response code constants 1054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 10622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat class VoldResponseCode { 1074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 100 series - Requestion action was initiated; expect another reply 1094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * before proceeding with a new command. 1104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 11122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeListResult = 110; 11222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int AsecListResult = 111; 113c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat public static final int StorageUsersListResult = 112; 11422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 200 series - Requestion action has been successfully completed. 1174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 1184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int ShareStatusResult = 210; 11922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int AsecPathResult = 211; 1204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int ShareEnabledResult = 212; 12122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 400 series - Command was accepted, but the requested action 1244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * did not take place. 1254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 1264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedNoMedia = 401; 1274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedMediaBlank = 402; 1284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedMediaCorrupt = 403; 1294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedVolNotMounted = 404; 130d970998b0d489774ad1c5b94b47d233912f00214San Mehat public static final int OpFailedStorageBusy = 405; 1312d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat public static final int OpFailedStorageNotFound = 406; 1324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 600 series - Unsolicited broadcasts. 1354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 13622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeStateChange = 605; 13722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int ShareAvailabilityChange = 620; 13822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeDiskInserted = 630; 13922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeDiskRemoved = 631; 14022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeBadRemoval = 632; 14122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 14222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private Context mContext; 1444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private NativeDaemonConnector mConnector; 1454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private String mLegacyState = Environment.MEDIA_REMOVED; 1464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private PackageManagerService mPms; 1474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private boolean mUmsEnabling; 1480eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Used as a lock for methods that register/unregister listeners. 1490eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu final private ArrayList<MountServiceBinderListener> mListeners = 1500eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu new ArrayList<MountServiceBinderListener>(); 1516a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private boolean mBooted = false; 1526a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private boolean mReady = false; 1536a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private boolean mSendUmsConnectedOnBoot = false; 154fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapu 1556cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat /** 1566cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat * Private hash of currently mounted secure containers. 1570eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * Used as a lock in methods to manipulate secure containers. 1586cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat */ 1590eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu final private HashSet<String> mAsecMountSet = new HashSet<String>(); 1606cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 16102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root /** 1623b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * The size of the crypto algorithm key in bits for OBB files. Currently 1633b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * Twofish is used which takes 128-bit keys. 1643b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root */ 1653b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128; 1663b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 1673b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root /** 1683b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * The number of times to run SHA1 in the PBKDF2 function for OBB files. 1693b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * 1024 is reasonably secure and not too slow. 1703b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root */ 1713b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root private static final int PBKDF2_HASH_ROUNDS = 1024; 1723b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 1733b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root /** 174a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * Mounted OBB tracking information. Used to track the current state of all 175a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * OBBs. 176a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root */ 177735de3b38abbd6564082a819377673ee593744a6Kenny Root final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>(); 178a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>(); 179a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 180a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class ObbState implements IBinder.DeathRecipient { 181af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root public ObbState(String filename, int callerUid, IObbActionListener token, int nonce) 182735de3b38abbd6564082a819377673ee593744a6Kenny Root throws RemoteException { 183a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root this.filename = filename; 184a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root this.callerUid = callerUid; 185af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root this.token = token; 186af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root this.nonce = nonce; 187a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 188a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 189a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // OBB source filename 190af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root String filename; 191a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 192a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Binder.callingUid() 19305105f7abe02b2dff91d6260b3628c8b97816babKenny Root final public int callerUid; 194a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 195af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Token of remote Binder caller 196af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IObbActionListener token; 197af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 198af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Identifier to pass back to the token 199af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final int nonce; 200a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 201735de3b38abbd6564082a819377673ee593744a6Kenny Root public IBinder getBinder() { 202735de3b38abbd6564082a819377673ee593744a6Kenny Root return token.asBinder(); 203735de3b38abbd6564082a819377673ee593744a6Kenny Root } 204735de3b38abbd6564082a819377673ee593744a6Kenny Root 205a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 206a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void binderDied() { 207a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbAction action = new UnmountObbAction(this, true); 208a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 209735de3b38abbd6564082a819377673ee593744a6Kenny Root } 210a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2115919ac6b4188285324646772501ef4b97b353cf4Kenny Root public void link() throws RemoteException { 2125919ac6b4188285324646772501ef4b97b353cf4Kenny Root getBinder().linkToDeath(this, 0); 2135919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 2145919ac6b4188285324646772501ef4b97b353cf4Kenny Root 2155919ac6b4188285324646772501ef4b97b353cf4Kenny Root public void unlink() { 216735de3b38abbd6564082a819377673ee593744a6Kenny Root getBinder().unlinkToDeath(this, 0); 217a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 21838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 21938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root @Override 22038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root public String toString() { 22138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root StringBuilder sb = new StringBuilder("ObbState{"); 22238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append("filename="); 22338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(filename); 22438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(",token="); 22538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(token.toString()); 22638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(",callerUid="); 22738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(callerUid); 22838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append('}'); 22938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return sb.toString(); 23038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 231a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 232a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 233a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // OBB Action Handler 234a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private ObbActionHandler mObbActionHandler; 235a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 236a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // OBB action handler messages 237a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_RUN_ACTION = 1; 238a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_BOUND = 2; 239a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_UNBIND = 3; 240a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_RECONNECT = 4; 241af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private static final int OBB_FLUSH_MOUNT_STATE = 5; 242a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 243a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root /* 244a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * Default Container Service information 24502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root */ 246a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName( 247a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService"); 248a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 249a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection(); 250a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 251a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class DefaultContainerConnection implements ServiceConnection { 252a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void onServiceConnected(ComponentName name, IBinder service) { 253a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 254a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "onServiceConnected"); 255a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service); 256a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs)); 257a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 258a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 259a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void onServiceDisconnected(ComponentName name) { 260a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 261a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "onServiceDisconnected"); 262a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 263a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root }; 264a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 265a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Used in the ObbActionHandler 266a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private IMediaContainerService mContainerService = null; 26702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 26802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root // Handler messages 269c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_PM_UPDATE = 1; 270c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_PM_DONE = 2; 271c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_MS = 3; 272c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int RETRY_UNMOUNT_DELAY = 30; // in ms 273c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int MAX_UNMOUNT_RETRIES = 4; 274c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 275c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu class UnmountCallBack { 27605105f7abe02b2dff91d6260b3628c8b97816babKenny Root final String path; 27705105f7abe02b2dff91d6260b3628c8b97816babKenny Root final boolean force; 278c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu int retries; 279c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 280c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack(String path, boolean force) { 281c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu retries = 0; 282c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu this.path = path; 283c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu this.force = force; 284c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 2850eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 2860eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu void handleFinished() { 287a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path); 2880eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doUnmountVolume(path, true); 2890eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 2900eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 2910eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 2920eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu class UmsEnableCallBack extends UnmountCallBack { 29305105f7abe02b2dff91d6260b3628c8b97816babKenny Root final String method; 2940eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 2950eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu UmsEnableCallBack(String path, String method, boolean force) { 2960eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu super(path, force); 2970eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu this.method = method; 2980eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 2990eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3000eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu @Override 3010eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu void handleFinished() { 3020eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu super.handleFinished(); 3030eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doShareUnshareVolume(path, method, true); 3040eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 305c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 306c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 3076ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu class ShutdownCallBack extends UnmountCallBack { 3086ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu IMountShutdownObserver observer; 3096ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu ShutdownCallBack(String path, IMountShutdownObserver observer) { 3106ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu super(path, true); 3116ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu this.observer = observer; 3126ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3136ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3146ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu @Override 3156ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu void handleFinished() { 3166ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int ret = doUnmountVolume(path, true); 3176ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (observer != null) { 3186ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu try { 3196ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu observer.onShutDownComplete(ret); 3206ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } catch (RemoteException e) { 321a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "RemoteException when shutting down"); 3226ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3236ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3246ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3256ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3266ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3275f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler class MountServiceHandler extends Handler { 328c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>(); 329e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu boolean mUpdatingStatus = false; 3306ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3315f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler MountServiceHandler(Looper l) { 3325f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler super(l); 3335f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler } 3345f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler 335c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu public void handleMessage(Message msg) { 336c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu switch (msg.what) { 337c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_PM_UPDATE: { 338a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_UPDATE"); 339c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = (UnmountCallBack) msg.obj; 340c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu mForceUnmounts.add(ucb); 341a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, " registered = " + mUpdatingStatus); 3426ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Register only if needed. 343e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu if (!mUpdatingStatus) { 344a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Updating external media status on PackageManager"); 345e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mUpdatingStatus = true; 346e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(false, true); 347c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 348c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 349c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 350c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_PM_DONE: { 351a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_DONE"); 352a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Updated status. Processing requests"); 353e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mUpdatingStatus = false; 3546ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int size = mForceUnmounts.size(); 3556ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int sizeArr[] = new int[size]; 3566ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int sizeArrN = 0; 3577af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Kill processes holding references first 3587af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ActivityManagerService ams = (ActivityManagerService) 3597af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ServiceManager.getService("activity"); 3606ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu for (int i = 0; i < size; i++) { 3616ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu UnmountCallBack ucb = mForceUnmounts.get(i); 3626ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu String path = ucb.path; 3636ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu boolean done = false; 3646ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (!ucb.force) { 365c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu done = true; 366c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } else { 3676ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int pids[] = getStorageUsers(path); 3686ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (pids == null || pids.length == 0) { 3696ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu done = true; 3706ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } else { 3716ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Eliminate system process here? 3727af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ams.killPids(pids, "unmount media"); 3737af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Confirm if file references have been freed. 3747af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu pids = getStorageUsers(path); 3757af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu if (pids == null || pids.length == 0) { 3767af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu done = true; 377c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 378c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 379c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 3807af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) { 3817af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Retry again 3827af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu Slog.i(TAG, "Retrying to kill storage users again"); 3837af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.sendMessageDelayed( 3847af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.obtainMessage(H_UNMOUNT_PM_DONE, 3857af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ucb.retries++), 3867af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu RETRY_UNMOUNT_DELAY); 387c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } else { 3886ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (ucb.retries >= MAX_UNMOUNT_RETRIES) { 3897af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu Slog.i(TAG, "Failed to unmount media inspite of " + 3907af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu MAX_UNMOUNT_RETRIES + " retries. Forcibly killing processes now"); 3916ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3927af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu sizeArr[sizeArrN++] = i; 3937af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS, 3947af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ucb)); 395c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 396c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 3976ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Remove already processed elements from list. 3986ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu for (int i = (sizeArrN-1); i >= 0; i--) { 3996ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu mForceUnmounts.remove(sizeArr[i]); 4006ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 401c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 402c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 403c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_MS : { 404a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_MS"); 405c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = (UnmountCallBack) msg.obj; 4060eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu ucb.handleFinished(); 407c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 408c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 409c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 410c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 411c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu }; 4125f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler final private HandlerThread mHandlerThread; 4135f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler final private Handler mHandler; 414c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 415207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void waitForReady() { 416207e538350665cea00e1aa70b8094beca4a34e45San Mehat while (mReady == false) { 417207e538350665cea00e1aa70b8094beca4a34e45San Mehat for (int retries = 5; retries > 0; retries--) { 418207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (mReady) { 419207e538350665cea00e1aa70b8094beca4a34e45San Mehat return; 420207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 421207e538350665cea00e1aa70b8094beca4a34e45San Mehat SystemClock.sleep(1000); 422207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 423a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Waiting too long for mReady!"); 424207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 4251f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 42602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 427207e538350665cea00e1aa70b8094beca4a34e45San Mehat private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onReceive(Context context, Intent intent) { 42991c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat String action = intent.getAction(); 43091c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 43191c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { 432207e538350665cea00e1aa70b8094beca4a34e45San Mehat mBooted = true; 43322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 434c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen /* 435c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * In the simulator, we need to broadcast a volume mounted event 436c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * to make the media scanner run. 437c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen */ 438c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen if ("simulator".equals(SystemProperties.get("ro.product.device"))) { 439c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen notifyVolumeStateChange(null, "/sdcard", VolumeState.NoMedia, VolumeState.Mounted); 440c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen return; 441c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen } 442fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat new Thread() { 443fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat public void run() { 444fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat try { 445fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat String path = Environment.getExternalStorageDirectory().getPath(); 4466a254403235196692b1769d2fe281b0852c0cc25San Mehat String state = getVolumeState(path); 4476a254403235196692b1769d2fe281b0852c0cc25San Mehat 4486a254403235196692b1769d2fe281b0852c0cc25San Mehat if (state.equals(Environment.MEDIA_UNMOUNTED)) { 449fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat int rc = doMountVolume(path); 450fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat if (rc != StorageResultCode.OperationSucceeded) { 451a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Boot-time mount failed (%d)", rc)); 452fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } 4536a254403235196692b1769d2fe281b0852c0cc25San Mehat } else if (state.equals(Environment.MEDIA_SHARED)) { 4546a254403235196692b1769d2fe281b0852c0cc25San Mehat /* 4556a254403235196692b1769d2fe281b0852c0cc25San Mehat * Bootstrap UMS enabled state since vold indicates 4566a254403235196692b1769d2fe281b0852c0cc25San Mehat * the volume is shared (runtime restart while ums enabled) 4576a254403235196692b1769d2fe281b0852c0cc25San Mehat */ 4586a254403235196692b1769d2fe281b0852c0cc25San Mehat notifyVolumeStateChange(null, path, VolumeState.NoMedia, VolumeState.Shared); 459fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } 4606a254403235196692b1769d2fe281b0852c0cc25San Mehat 4616a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat /* 4626a254403235196692b1769d2fe281b0852c0cc25San Mehat * If UMS was connected on boot, send the connected event 4636a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat * now that we're up. 4646a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat */ 4656a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat if (mSendUmsConnectedOnBoot) { 4666a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat sendUmsIntent(true); 4676a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat mSendUmsConnectedOnBoot = false; 4686a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } 469fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } catch (Exception ex) { 470a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Boot-time mount exception", ex); 471fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } 472207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 473fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat }.start(); 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private final class MountServiceBinderListener implements IBinder.DeathRecipient { 4794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final IMountServiceListener mListener; 48091c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 4814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener(IMountServiceListener listener) { 4824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListener = listener; 48302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 48491c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 48591c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 4864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void binderDied() { 487a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!"); 488a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root synchronized (mListeners) { 4894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(this); 4904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListener.asBinder().unlinkToDeath(this, 0); 49191c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 49291c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 49391c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 49491c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 4950eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private void doShareUnshareVolume(String path, String method, boolean enable) { 4964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat // TODO: Add support for multiple share methods 4974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!method.equals("ums")) { 4984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new IllegalArgumentException(String.format("Method %s not supported", method)); 4997fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 5024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(String.format( 5034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat "volume %sshare %s %s", (enable ? "" : "un"), path, method)); 5044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 505a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to share/unshare", e); 50622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 509207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void updatePublicVolumeState(String path, String state) { 5104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!path.equals(Environment.getExternalStorageDirectory().getPath())) { 511a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Multiple volumes not currently supported"); 5127fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat return; 5137fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 514b104340496e3a531e26c8f428c808eca0e039f50San Mehat 515b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (mLegacyState.equals(state)) { 516a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, String.format("Duplicate state transition (%s -> %s)", mLegacyState, state)); 517b104340496e3a531e26c8f428c808eca0e039f50San Mehat return; 518b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 519af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 5208a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (Environment.MEDIA_UNMOUNTED.equals(state)) { 521af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Tell the package manager the media is gone. 522e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(false, false); 523af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 524af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root /* 525af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * Some OBBs might have been unmounted when this volume was 526af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * unmounted, so send a message to the handler to let it know to 527af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * remove those from the list of mounted OBBS. 528af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root */ 529af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_FLUSH_MOUNT_STATE, 530af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root path)); 5318a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } else if (Environment.MEDIA_MOUNTED.equals(state)) { 532af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Tell the package manager the media is available for use. 533e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(true, false); 5348a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 53538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 5364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String oldState = mLegacyState; 5374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mLegacyState = state; 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 5404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for (int i = mListeners.size() -1; i >= 0; i--) { 5414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = mListeners.get(i); 5424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 543b104340496e3a531e26c8f428c808eca0e039f50San Mehat bl.mListener.onStorageStateChanged(path, oldState, state); 5444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 545a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener dead"); 5464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(i); 5474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 548a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener failed", ex); 5494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 55422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat /** 55522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * 55622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * Callback from NativeDaemonConnector 55722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat */ 55822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public void onDaemonConnected() { 5595b77dab23469273d41f9c530d947ac055765e6eaSan Mehat /* 5605b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * Since we'll be calling back into the NativeDaemonConnector, 5615b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * we need to do our work in a new thread. 5625b77dab23469273d41f9c530d947ac055765e6eaSan Mehat */ 5637fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat new Thread() { 5647fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public void run() { 5655b77dab23469273d41f9c530d947ac055765e6eaSan Mehat /** 5665b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * Determine media state and UMS detection status 5675b77dab23469273d41f9c530d947ac055765e6eaSan Mehat */ 5685b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String path = Environment.getExternalStorageDirectory().getPath(); 5695b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String state = Environment.MEDIA_REMOVED; 5705b77dab23469273d41f9c530d947ac055765e6eaSan Mehat 5717fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat try { 5725b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String[] vols = mConnector.doListCommand( 5734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat "volume list", VoldResponseCode.VolumeListResult); 5745b77dab23469273d41f9c530d947ac055765e6eaSan Mehat for (String volstr : vols) { 5755b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String[] tok = volstr.split(" "); 5765b77dab23469273d41f9c530d947ac055765e6eaSan Mehat // FMT: <label> <mountpoint> <state> 5775b77dab23469273d41f9c530d947ac055765e6eaSan Mehat if (!tok[1].equals(path)) { 578a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, String.format( 5795b77dab23469273d41f9c530d947ac055765e6eaSan Mehat "Skipping unknown volume '%s'",tok[1])); 5805b77dab23469273d41f9c530d947ac055765e6eaSan Mehat continue; 5815b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } 5825b77dab23469273d41f9c530d947ac055765e6eaSan Mehat int st = Integer.parseInt(tok[2]); 5835b77dab23469273d41f9c530d947ac055765e6eaSan Mehat if (st == VolumeState.NoMedia) { 5845b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_REMOVED; 5855b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Idle) { 586207e538350665cea00e1aa70b8094beca4a34e45San Mehat state = Environment.MEDIA_UNMOUNTED; 5875b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Mounted) { 5885b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_MOUNTED; 589a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Media already mounted on daemon connection"); 5905b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Shared) { 5915b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_SHARED; 592a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Media shared on daemon connection"); 5935b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else { 5945b77dab23469273d41f9c530d947ac055765e6eaSan Mehat throw new Exception(String.format("Unexpected state %d", st)); 5957fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 5967fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 597c2a39471642e31d7350910612e40d078b825173aSan Mehat if (state != null) { 598a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state); 599c2a39471642e31d7350910612e40d078b825173aSan Mehat updatePublicVolumeState(path, state); 600c2a39471642e31d7350910612e40d078b825173aSan Mehat } 6015b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } catch (Exception e) { 602a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Error processing initial volume state", e); 6035b77dab23469273d41f9c530d947ac055765e6eaSan Mehat updatePublicVolumeState(path, Environment.MEDIA_REMOVED); 6047fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6057fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 6067fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat try { 607207e538350665cea00e1aa70b8094beca4a34e45San Mehat boolean avail = doGetShareMethodAvailable("ums"); 6087fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat notifyShareAvailabilityChange("ums", avail); 6097fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } catch (Exception ex) { 610a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Failed to get share availability"); 6117fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 612207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 613207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Now that we've done our initialization, release 614207e538350665cea00e1aa70b8094beca4a34e45San Mehat * the hounds! 615207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 616207e538350665cea00e1aa70b8094beca4a34e45San Mehat mReady = true; 6177fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6187fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat }.start(); 6197fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6207fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 62122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat /** 62222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * Callback from NativeDaemonConnector 62322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat */ 62422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public boolean onEvent(int code, String raw, String[] cooked) { 6254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Intent in = null; 6264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 6278a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (DEBUG_EVENTS) { 6288a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu StringBuilder builder = new StringBuilder(); 6298a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append("onEvent::"); 6308a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" raw= " + raw); 6318a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (cooked != null) { 6328a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" cooked = " ); 6338a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu for (String str : cooked) { 6348a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" " + str); 6358a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 6368a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 637a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, builder.toString()); 6388a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 63922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat if (code == VoldResponseCode.VolumeStateChange) { 6404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 6414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * One of the volumes we're managing has changed state. 6424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Format: "NNN Volume <label> <path> state changed 6434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * from <old_#> (<old_str>) to <new_#> (<new_str>)" 6444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 64522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat notifyVolumeStateChange( 64622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat cooked[2], cooked[3], Integer.parseInt(cooked[7]), 64722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat Integer.parseInt(cooked[10])); 64822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else if (code == VoldResponseCode.ShareAvailabilityChange) { 64922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Share method <method> now <available|unavailable> 65022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat boolean avail = false; 65122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat if (cooked[5].equals("available")) { 65222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat avail = true; 65322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 65422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat notifyShareAvailabilityChange(cooked[3], avail); 6554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if ((code == VoldResponseCode.VolumeDiskInserted) || 6564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat (code == VoldResponseCode.VolumeDiskRemoved) || 6574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat (code == VoldResponseCode.VolumeBadRemoval)) { 65822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>) 65922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>) 66022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>) 6614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final String label = cooked[2]; 6624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final String path = cooked[3]; 6634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int major = -1; 6644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int minor = -1; 6654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 6664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 6674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String devComp = cooked[6].substring(1, cooked[6].length() -1); 6684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String[] devTok = devComp.split(":"); 6694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat major = Integer.parseInt(devTok[0]); 6704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat minor = Integer.parseInt(devTok[1]); 6714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 672a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to parse major/minor", ex); 6734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 6754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (code == VoldResponseCode.VolumeDiskInserted) { 6764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat new Thread() { 6774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void run() { 6784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 6794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int rc; 680b104340496e3a531e26c8f428c808eca0e039f50San Mehat if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { 681a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, String.format("Insertion mount failed (%d)", rc)); 6824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 684a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Failed to mount media on insertion", ex); 6854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat }.start(); 6884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (code == VoldResponseCode.VolumeDiskRemoved) { 6894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 6904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * This event gets trumped if we're already in BAD_REMOVAL state 6914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 6924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) { 6934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return true; 6944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 696a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first"); 6974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 6984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); 6994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 7004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 701a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed"); 7024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_REMOVED); 7034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_REMOVED, Uri.parse("file://" + path)); 7044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (code == VoldResponseCode.VolumeBadRemoval) { 705a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first"); 7064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 7074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 7084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); 7094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 7104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 711a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal"); 7124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL); 7134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL, Uri.parse("file://" + path)); 7144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else { 715a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Unknown code {%d}", code)); 7164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 71722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else { 71822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat return false; 71922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 7204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 7214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (in != null) { 7224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 7235f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler } 7245f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler return true; 72522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 72622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 727207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void notifyVolumeStateChange(String label, String path, int oldState, int newState) { 7284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String vs = getVolumeState(path); 729a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChanged::" + vs); 7304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 7314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Intent in = null; 7327fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 733bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood if (oldState == VolumeState.Shared && newState != oldState) { 734a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent"); 735bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_UNSHARED, 736bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood Uri.parse("file://" + path))); 737bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood } 738bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood 7397fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat if (newState == VolumeState.Init) { 7407fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.NoMedia) { 7417fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat // NoMedia is handled via Disk Remove events 7427fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Idle) { 7435fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat /* 7445fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or 7455fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat * if we're in the process of enabling UMS 7465fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat */ 7474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!vs.equals( 7484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Environment.MEDIA_BAD_REMOVAL) && !vs.equals( 7494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Environment.MEDIA_NOFS) && !vs.equals( 7500eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) { 751a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable"); 7524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 7534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); 7547fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 7557fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Pending) { 7567fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Checking) { 757a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking"); 7584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_CHECKING); 7594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_CHECKING, Uri.parse("file://" + path)); 7607fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Mounted) { 761a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted"); 7624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_MOUNTED); 7634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + path)); 7644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in.putExtra("read-only", false); 7657fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Unmounting) { 7664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_EJECT, Uri.parse("file://" + path)); 7677fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Formatting) { 7687fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Shared) { 769a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted"); 7704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 7714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 7724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); 7734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 7744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 775a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared"); 7764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_SHARED); 7774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_SHARED, Uri.parse("file://" + path)); 778a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent"); 7797fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.SharedMnt) { 780a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Live shared mounts not supported yet!"); 7814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return; 7827fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else { 783a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Unhandled VolumeState {" + newState + "}"); 7847fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 7857fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 7864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (in != null) { 7874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 791207e538350665cea00e1aa70b8094beca4a34e45San Mehat private boolean doGetShareMethodAvailable(String method) { 79285fb20665feadda526ad422c093b859e8c4d40bcKenny Root ArrayList<String> rsp; 793a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root try { 79485fb20665feadda526ad422c093b859e8c4d40bcKenny Root rsp = mConnector.doCommand("share status " + method); 795a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } catch (NativeDaemonConnectorException ex) { 796a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root Slog.e(TAG, "Failed to determine whether share method " + method + " is available."); 797a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return false; 798a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } 799207e538350665cea00e1aa70b8094beca4a34e45San Mehat 800207e538350665cea00e1aa70b8094beca4a34e45San Mehat for (String line : rsp) { 801a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root String[] tok = line.split(" "); 802a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root if (tok.length < 3) { 803a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root Slog.e(TAG, "Malformed response to share status " + method); 804a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return false; 805a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } 806a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root 807207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code; 808207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 809207e538350665cea00e1aa70b8094beca4a34e45San Mehat code = Integer.parseInt(tok[0]); 810207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NumberFormatException nfe) { 811a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Error parsing code %s", tok[0])); 812207e538350665cea00e1aa70b8094beca4a34e45San Mehat return false; 813207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 814207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.ShareStatusResult) { 815207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (tok[2].equals("available")) 816207e538350665cea00e1aa70b8094beca4a34e45San Mehat return true; 817207e538350665cea00e1aa70b8094beca4a34e45San Mehat return false; 818207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 819a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Unexpected response code %d", code)); 820207e538350665cea00e1aa70b8094beca4a34e45San Mehat return false; 821207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 822207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 823a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Got an empty response"); 824207e538350665cea00e1aa70b8094beca4a34e45San Mehat return false; 825207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 826207e538350665cea00e1aa70b8094beca4a34e45San Mehat 827207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doMountVolume(String path) { 828b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 829207e538350665cea00e1aa70b8094beca4a34e45San Mehat 830a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path); 831207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 832207e538350665cea00e1aa70b8094beca4a34e45San Mehat mConnector.doCommand(String.format("volume mount %s", path)); 833207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 834207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 835207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Mount failed for some reason 836207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 837207e538350665cea00e1aa70b8094beca4a34e45San Mehat Intent in = null; 838207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 839207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedNoMedia) { 840207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 841207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Attempt to mount but no media inserted 842207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 843b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedNoMedia; 844207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaBlank) { 845a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs"); 846207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 847207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Media is blank or does not contain a supported filesystem 848207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 849207e538350665cea00e1aa70b8094beca4a34e45San Mehat updatePublicVolumeState(path, Environment.MEDIA_NOFS); 850207e538350665cea00e1aa70b8094beca4a34e45San Mehat in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path)); 851b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedMediaBlank; 852207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { 853a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state media corrupt"); 854207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 855207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Volume consistency check failed 856207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 857207e538350665cea00e1aa70b8094beca4a34e45San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE); 858207e538350665cea00e1aa70b8094beca4a34e45San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path)); 859b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedMediaCorrupt; 860207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 861b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 862207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 863207e538350665cea00e1aa70b8094beca4a34e45San Mehat 864207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 865207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Send broadcast intent (if required for the failure) 866207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 867207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (in != null) { 868207e538350665cea00e1aa70b8094beca4a34e45San Mehat mContext.sendBroadcast(in); 869207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 870207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 871207e538350665cea00e1aa70b8094beca4a34e45San Mehat 872207e538350665cea00e1aa70b8094beca4a34e45San Mehat return rc; 873207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 874207e538350665cea00e1aa70b8094beca4a34e45San Mehat 875c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu /* 876c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * If force is not set, we do not unmount if there are 877c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * processes holding references to the volume about to be unmounted. 878c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * If force is set, all the processes holding references need to be 879c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * killed via the ActivityManager before actually unmounting the volume. 880c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * This might even take a while and might be retried after timed delays 881c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * to make sure we dont end up in an instable state and kill some core 882c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * processes. 883c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu */ 884d970998b0d489774ad1c5b94b47d233912f00214San Mehat private int doUnmountVolume(String path, boolean force) { 88559443a673a736978361dc341f41ce4e9dae053a0San Mehat if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) { 886207e538350665cea00e1aa70b8094beca4a34e45San Mehat return VoldResponseCode.OpFailedVolNotMounted; 887207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 888aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 889aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 890aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 891aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 892aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 893aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 894aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 895aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 896aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 897c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu // Redundant probably. But no harm in updating state again. 898e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(false, false); 899207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 900d970998b0d489774ad1c5b94b47d233912f00214San Mehat mConnector.doCommand(String.format( 901d970998b0d489774ad1c5b94b47d233912f00214San Mehat "volume unmount %s%s", path, (force ? " force" : ""))); 902e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu // We unmounted the volume. None of the asec containers are available now. 903e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu synchronized (mAsecMountSet) { 904e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mAsecMountSet.clear(); 905e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu } 906b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationSucceeded; 907207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 908207e538350665cea00e1aa70b8094beca4a34e45San Mehat // Don't worry about mismatch in PackageManager since the 909207e538350665cea00e1aa70b8094beca4a34e45San Mehat // call back will handle the status changes any way. 910207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 911207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedVolNotMounted) { 912a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageNotMounted; 913d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else if (code == VoldResponseCode.OpFailedStorageBusy) { 914d970998b0d489774ad1c5b94b47d233912f00214San Mehat return StorageResultCode.OperationFailedStorageBusy; 915207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 916b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedInternalError; 917207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 918207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 919207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 920207e538350665cea00e1aa70b8094beca4a34e45San Mehat 921207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doFormatVolume(String path) { 922207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 923207e538350665cea00e1aa70b8094beca4a34e45San Mehat String cmd = String.format("volume format %s", path); 924207e538350665cea00e1aa70b8094beca4a34e45San Mehat mConnector.doCommand(cmd); 925b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationSucceeded; 926207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 927207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 928207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedNoMedia) { 929b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedNoMedia; 930207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { 931b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedMediaCorrupt; 932207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 933b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedInternalError; 934207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 935207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 936207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 937207e538350665cea00e1aa70b8094beca4a34e45San Mehat 938b104340496e3a531e26c8f428c808eca0e039f50San Mehat private boolean doGetVolumeShared(String path, String method) { 939b104340496e3a531e26c8f428c808eca0e039f50San Mehat String cmd = String.format("volume shared %s %s", path, method); 940a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root ArrayList<String> rsp; 941a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root 942a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root try { 943a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root rsp = mConnector.doCommand(cmd); 944a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } catch (NativeDaemonConnectorException ex) { 945a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root Slog.e(TAG, "Failed to read response to volume shared " + path + " " + method); 946a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return false; 947a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } 948b104340496e3a531e26c8f428c808eca0e039f50San Mehat 949b104340496e3a531e26c8f428c808eca0e039f50San Mehat for (String line : rsp) { 950a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root String[] tok = line.split(" "); 951a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root if (tok.length < 3) { 952a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root Slog.e(TAG, "Malformed response to volume shared " + path + " " + method + " command"); 953a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return false; 954a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } 955a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root 956b104340496e3a531e26c8f428c808eca0e039f50San Mehat int code; 957b104340496e3a531e26c8f428c808eca0e039f50San Mehat try { 958b104340496e3a531e26c8f428c808eca0e039f50San Mehat code = Integer.parseInt(tok[0]); 959b104340496e3a531e26c8f428c808eca0e039f50San Mehat } catch (NumberFormatException nfe) { 960a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Error parsing code %s", tok[0])); 961b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 962b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 963b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (code == VoldResponseCode.ShareEnabledResult) { 964a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return "enabled".equals(tok[2]); 965b104340496e3a531e26c8f428c808eca0e039f50San Mehat } else { 966a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Unexpected response code %d", code)); 967b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 968b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 969b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 970a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Got an empty response"); 971b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 972b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 973b104340496e3a531e26c8f428c808eca0e039f50San Mehat 974207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void notifyShareAvailabilityChange(String method, final boolean avail) { 9757fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat if (!method.equals("ums")) { 976a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Ignoring unsupported share method {" + method + "}"); 9777fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat return; 9787fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 9791f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat 9804270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 9814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for (int i = mListeners.size() -1; i >= 0; i--) { 9824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = mListeners.get(i); 9831f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat try { 984b104340496e3a531e26c8f428c808eca0e039f50San Mehat bl.mListener.onUsbMassStorageConnectionChanged(avail); 9854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 986a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener dead"); 9874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(i); 9881f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } catch (Exception ex) { 989a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener failed", ex); 9901f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 9911f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 9924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 9937fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 994207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (mBooted == true) { 9956a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat sendUmsIntent(avail); 9966a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } else { 9976a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat mSendUmsConnectedOnBoot = avail; 9981f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 9992fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat 10002fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat final String path = Environment.getExternalStorageDirectory().getPath(); 10012fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat if (avail == false && getVolumeState(path).equals(Environment.MEDIA_SHARED)) { 10022fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat /* 10032fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat * USB mass storage disconnected while enabled 10042fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat */ 10052fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat new Thread() { 10062fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat public void run() { 10072fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat try { 10082fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat int rc; 1009a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Disabling UMS after cable disconnect"); 10102fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat doShareUnshareVolume(path, "ums", false); 10112fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { 1012a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format( 10132fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat "Failed to remount {%s} on UMS enabled-disconnect (%d)", 10142fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat path, rc)); 10152fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 10162fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } catch (Exception ex) { 1017a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Failed to mount media on UMS enabled-disconnect", ex); 10182fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 10192fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 10202fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat }.start(); 10212fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10246a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private void sendUmsIntent(boolean c) { 10256a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat mContext.sendBroadcast( 10266a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat new Intent((c ? Intent.ACTION_UMS_CONNECTED : Intent.ACTION_UMS_DISCONNECTED))); 10276a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } 10286a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat 1029207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void validatePermission(String perm) { 10304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) { 10314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new SecurityException(String.format("Requires %s permission", perm)); 10324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 10337fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 10347fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1036207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Constructs a new MountService instance 1037207e538350665cea00e1aa70b8094beca4a34e45San Mehat * 1038207e538350665cea00e1aa70b8094beca4a34e45San Mehat * @param context Binder context for this service 1039207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 1040207e538350665cea00e1aa70b8094beca4a34e45San Mehat public MountService(Context context) { 1041207e538350665cea00e1aa70b8094beca4a34e45San Mehat mContext = context; 1042207e538350665cea00e1aa70b8094beca4a34e45San Mehat 1043207e538350665cea00e1aa70b8094beca4a34e45San Mehat // XXX: This will go away soon in favor of IMountServiceObserver 1044207e538350665cea00e1aa70b8094beca4a34e45San Mehat mPms = (PackageManagerService) ServiceManager.getService("package"); 1045207e538350665cea00e1aa70b8094beca4a34e45San Mehat 1046207e538350665cea00e1aa70b8094beca4a34e45San Mehat mContext.registerReceiver(mBroadcastReceiver, 1047207e538350665cea00e1aa70b8094beca4a34e45San Mehat new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); 1048207e538350665cea00e1aa70b8094beca4a34e45San Mehat 10495f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandlerThread = new HandlerThread("MountService"); 10505f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandlerThread.start(); 10515f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandler = new MountServiceHandler(mHandlerThread.getLooper()); 10525f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler 1053a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Add OBB Action Handler to MountService thread. 1054a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper()); 1055a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1056c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen /* 1057c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * Vold does not run in the simulator, so pretend the connector thread 1058c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * ran and did its thing. 1059c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen */ 1060c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen if ("simulator".equals(SystemProperties.get("ro.product.device"))) { 1061c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen mReady = true; 1062c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen mUmsEnabling = true; 1063c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen return; 1064c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen } 1065c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen 1066305bcbf0c961840c4505770d084a1caacc074dbbKenny Root /* 1067305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * Create the connection to vold with a maximum queue of twice the 1068305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * amount of containers we'd ever expect to have. This keeps an 1069305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * "asec list" from blocking a thread repeatedly. 1070305bcbf0c961840c4505770d084a1caacc074dbbKenny Root */ 1071305bcbf0c961840c4505770d084a1caacc074dbbKenny Root mConnector = new NativeDaemonConnector(this, "vold", 1072305bcbf0c961840c4505770d084a1caacc074dbbKenny Root PackageManagerService.MAX_CONTAINERS * 2, VOLD_TAG); 1073207e538350665cea00e1aa70b8094beca4a34e45San Mehat mReady = false; 1074305bcbf0c961840c4505770d084a1caacc074dbbKenny Root Thread thread = new Thread(mConnector, VOLD_TAG); 1075207e538350665cea00e1aa70b8094beca4a34e45San Mehat thread.start(); 1076207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1077207e538350665cea00e1aa70b8094beca4a34e45San Mehat 1078207e538350665cea00e1aa70b8094beca4a34e45San Mehat /** 10794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Exposed API calls below here 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10817fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 10824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void registerListener(IMountServiceListener listener) { 10834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 10844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = new MountServiceBinderListener(listener); 10854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 10864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat listener.asBinder().linkToDeath(bl, 0); 10874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.add(bl); 10884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 1089a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to link to listener death"); 10904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 10917fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void unregisterListener(IMountServiceListener listener) { 10954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 10964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for(MountServiceBinderListener bl : mListeners) { 10974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (bl.mListener == listener) { 10984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(mListeners.indexOf(bl)); 10994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return; 11004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 11014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11056ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu public void shutdown(final IMountShutdownObserver observer) { 11064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.SHUTDOWN); 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1108a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Shutting down"); 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String path = Environment.getExternalStorageDirectory().getPath(); 11114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String state = getVolumeState(path); 11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (state.equals(Environment.MEDIA_SHARED)) { 11144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 11154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * If the media is currently shared, unshare it. 11164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * XXX: This is still dangerous!. We should not 11174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * be rebooting at *all* if UMS is enabled, since 11184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * the UMS host could have dirty FAT cache entries 11194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * yet to flush. 11204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 11210eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu setUsbMassStorageEnabled(false); 11224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (state.equals(Environment.MEDIA_CHECKING)) { 11234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 11244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * If the media is being checked, then we need to wait for 11254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * it to complete before being able to proceed. 11264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 11274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat // XXX: @hackbod - Should we disable the ANR timer here? 11284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int retries = 30; 11294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) { 11304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 11314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Thread.sleep(1000); 11324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (InterruptedException iex) { 1133a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Interrupted while waiting for media", iex); 11344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat break; 11354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 11364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat state = Environment.getExternalStorageState(); 11374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 11384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (retries == 0) { 1139a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Timed out waiting for media to check"); 11404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 11417fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 11427fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 11434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (state.equals(Environment.MEDIA_MOUNTED)) { 11446ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Post a unmount message. 11456ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu ShutdownCallBack ucb = new ShutdownCallBack(path, observer); 11466ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb)); 11471f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11500eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private boolean getUmsEnabling() { 11510eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu synchronized (mListeners) { 11520eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu return mUmsEnabling; 11530eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 11540eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 11550eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 11560eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private void setUmsEnabling(boolean enable) { 11570eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu synchronized (mListeners) { 11580eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu mUmsEnabling = true; 11590eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 11600eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 11610eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 1162b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageConnected() { 1163207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 11647fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 11650eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (getUmsEnabling()) { 1166b104340496e3a531e26c8f428c808eca0e039f50San Mehat return true; 1167b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1168b104340496e3a531e26c8f428c808eca0e039f50San Mehat return doGetShareMethodAvailable("ums"); 11694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11710eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu public void setUsbMassStorageEnabled(boolean enable) { 1172207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 11730eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 11740eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 11750eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // TODO: Add support for multiple share methods 1176b104340496e3a531e26c8f428c808eca0e039f50San Mehat 11770eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 11780eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * If the volume is mounted and we're enabling then unmount it 11790eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 11800eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String path = Environment.getExternalStorageDirectory().getPath(); 11810eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String vs = getVolumeState(path); 11820eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String method = "ums"; 11830eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (enable && vs.equals(Environment.MEDIA_MOUNTED)) { 11840eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Override for isUsbMassStorageEnabled() 11850eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu setUmsEnabling(enable); 11860eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true); 11870eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb)); 11880eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Clear override 11890eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu setUmsEnabling(false); 11900eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 11910eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 11920eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * If we disabled UMS then mount the volume 11930eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 11940eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (!enable) { 11950eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doShareUnshareVolume(path, method, enable); 11960eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (doMountVolume(path) != StorageResultCode.OperationSucceeded) { 1197a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to remount " + path + 11980eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu " after disabling share method " + method); 11990eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 12000eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * Even though the mount failed, the unshare didn't so don't indicate an error. 12010eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * The mountVolume() call will have set the storage state and sent the necessary 12020eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * broadcasts. 12030eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 12040eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 12050eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 12064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1208b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageEnabled() { 1209207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1210b104340496e3a531e26c8f428c808eca0e039f50San Mehat return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums"); 12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * @return state of the volume at the specified mount point 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String getVolumeState(String mountPoint) { 12174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 12184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * XXX: Until we have multiple volume discovery, just hardwire 12194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * this to /sdcard 12204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 12214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) { 1222a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume"); 12234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new IllegalArgumentException(); 12244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 12254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 12264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return mLegacyState; 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 12294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int mountVolume(String path) { 12304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1232207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1233207e538350665cea00e1aa70b8094beca4a34e45San Mehat return doMountVolume(path); 12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1236c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu public void unmountVolume(String path, boolean force) { 12374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1238207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12408a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu String volState = getVolumeState(path); 1241a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path + " force = " + force); 12428a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (Environment.MEDIA_UNMOUNTED.equals(volState) || 12438a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_REMOVED.equals(volState) || 12448a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_SHARED.equals(volState) || 12458a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_UNMOUNTABLE.equals(volState)) { 12468a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // Media already unmounted or cannot be unmounted. 12478a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // TODO return valid return code when adding observer call back. 12488a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu return; 12498a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 1250c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = new UnmountCallBack(path, force); 1251c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb)); 12524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int formatVolume(String path) { 12554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); 1256207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1258207e538350665cea00e1aa70b8094beca4a34e45San Mehat return doFormatVolume(path); 12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12603697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1261c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat public int []getStorageUsers(String path) { 1262c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1263c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat waitForReady(); 1264c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat try { 1265c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat String[] r = mConnector.doListCommand( 1266c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat String.format("storage users %s", path), 1267c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat VoldResponseCode.StorageUsersListResult); 1268c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat // FMT: <pid> <process name> 1269c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat int[] data = new int[r.length]; 1270c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat for (int i = 0; i < r.length; i++) { 1271c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat String []tok = r[i].split(" "); 1272c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat try { 1273c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat data[i] = Integer.parseInt(tok[0]); 1274c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } catch (NumberFormatException nfe) { 1275a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Error parsing pid %s", tok[0])); 1276c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return new int[0]; 1277c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1278c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1279c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return data; 1280c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } catch (NativeDaemonConnectorException e) { 1281a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to retrieve storage users list", e); 1282c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return new int[0]; 1283c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1284c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1285c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat 1286b104340496e3a531e26c8f428c808eca0e039f50San Mehat private void warnOnNotMounted() { 1287b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 1288a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "getSecureContainerList() called when storage not mounted"); 1289b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1290b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1291b104340496e3a531e26c8f428c808eca0e039f50San Mehat 12924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String[] getSecureContainerList() { 12934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 1294207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1295b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1296f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 12974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 12984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult); 12994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 13004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return new String[0]; 130102735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 13023697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 13033697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 13044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int createSecureContainer(String id, int sizeMb, String fstype, 13054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String key, int ownerUid) { 13064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_CREATE); 1307207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1308b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 13094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1310b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 13114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String cmd = String.format("asec create %s %d %s %s %d", id, sizeMb, fstype, key, ownerUid); 13124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 13134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 13144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1315b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 131602735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1317a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1318a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (rc == StorageResultCode.OperationSucceeded) { 1319a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1320a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat mAsecMountSet.add(id); 1321a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1322a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 13234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 13243697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 13253697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 13264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int finalizeSecureContainer(String id) { 13274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_CREATE); 1328b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 13294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1330b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 13314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 13324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(String.format("asec finalize %s", id)); 1333a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat /* 1334a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat * Finalization does a remount, so no need 1335a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat * to update mAsecMountSet 1336a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat */ 13374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1338b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 133902735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 13404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 13413697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 13423697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1343d970998b0d489774ad1c5b94b47d233912f00214San Mehat public int destroySecureContainer(String id, boolean force) { 13444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_DESTROY); 1345207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1346b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1347f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 1348aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 1349aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 1350aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 1351aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 1352aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 1353aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 1354aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 1355aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 1356b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 13574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1358d970998b0d489774ad1c5b94b47d233912f00214San Mehat mConnector.doCommand(String.format("asec destroy %s%s", id, (force ? " force" : ""))); 13594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1360d970998b0d489774ad1c5b94b47d233912f00214San Mehat int code = e.getCode(); 1361d970998b0d489774ad1c5b94b47d233912f00214San Mehat if (code == VoldResponseCode.OpFailedStorageBusy) { 1362d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedStorageBusy; 1363d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else { 1364d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedInternalError; 1365d970998b0d489774ad1c5b94b47d233912f00214San Mehat } 136602735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1367a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1368a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (rc == StorageResultCode.OperationSucceeded) { 1369a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1370a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (mAsecMountSet.contains(id)) { 1371a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat mAsecMountSet.remove(id); 1372a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1373a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1374a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1375a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 13764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 13773697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 13783697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 13794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int mountSecureContainer(String id, String key, int ownerUid) { 13804270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 1381207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1382b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 13834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1384a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1385a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (mAsecMountSet.contains(id)) { 1386a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageMounted; 1387a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1388a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1389a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1390b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 13914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String cmd = String.format("asec mount %s %s %d", id, key, ownerUid); 13924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 13934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 13944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1395f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root int code = e.getCode(); 1396f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root if (code != VoldResponseCode.OpFailedStorageBusy) { 1397f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root rc = StorageResultCode.OperationFailedInternalError; 1398f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root } 139902735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 14006cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 14016cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (rc == StorageResultCode.OperationSucceeded) { 14026cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 14036cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat mAsecMountSet.add(id); 14046cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 14056cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 14064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 14073697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 14083697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1409d970998b0d489774ad1c5b94b47d233912f00214San Mehat public int unmountSecureContainer(String id, boolean force) { 14104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 1411207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1412b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 14134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 14146cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 14156cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (!mAsecMountSet.contains(id)) { 1416a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageNotMounted; 14176cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 14186cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 14196cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 1420aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 1421aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 1422aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 1423aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 1424aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 1425aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 1426aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 1427aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 1428b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 1429d970998b0d489774ad1c5b94b47d233912f00214San Mehat String cmd = String.format("asec unmount %s%s", id, (force ? " force" : "")); 14304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 14314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 14324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1433d970998b0d489774ad1c5b94b47d233912f00214San Mehat int code = e.getCode(); 1434d970998b0d489774ad1c5b94b47d233912f00214San Mehat if (code == VoldResponseCode.OpFailedStorageBusy) { 1435d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedStorageBusy; 1436d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else { 1437d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedInternalError; 1438d970998b0d489774ad1c5b94b47d233912f00214San Mehat } 143902735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 14406cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 14416cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (rc == StorageResultCode.OperationSucceeded) { 14426cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 14436cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat mAsecMountSet.remove(id); 14446cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 14456cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 14464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 14479dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat } 14489dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat 14496cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat public boolean isSecureContainerMounted(String id) { 14506cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 14516cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat waitForReady(); 14526cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat warnOnNotMounted(); 14536cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 14546cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 14556cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat return mAsecMountSet.contains(id); 14566cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 14576cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 14586cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 14594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int renameSecureContainer(String oldId, String newId) { 14604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_RENAME); 1461207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1462b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 14634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1464a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 146585451ee15fdf6cae371dc3005441988c7d426401San Mehat /* 146685451ee15fdf6cae371dc3005441988c7d426401San Mehat * Because a mounted container has active internal state which cannot be 146785451ee15fdf6cae371dc3005441988c7d426401San Mehat * changed while active, we must ensure both ids are not currently mounted. 146885451ee15fdf6cae371dc3005441988c7d426401San Mehat */ 146985451ee15fdf6cae371dc3005441988c7d426401San Mehat if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) { 1470a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageMounted; 1471a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1472a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1473a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1474b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 14754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String cmd = String.format("asec rename %s %s", oldId, newId); 14764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 14774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 14784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1479b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 148002735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1481a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 14824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 148345f61040823d8c442838f75cde8760f236603daeSan Mehat } 148445f61040823d8c442838f75cde8760f236603daeSan Mehat 14854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String getSecureContainerPath(String id) { 14864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 1487207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1488b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1489f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 14902d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat try { 14912d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat ArrayList<String> rsp = mConnector.doCommand(String.format("asec path %s", id)); 14922d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat String []tok = rsp.get(0).split(" "); 149322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat int code = Integer.parseInt(tok[0]); 14942d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat if (code != VoldResponseCode.AsecPathResult) { 14952d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat throw new IllegalStateException(String.format("Unexpected response code %d", code)); 14962d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat } 14972d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat return tok[1]; 14982d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat } catch (NativeDaemonConnectorException e) { 14992d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat int code = e.getCode(); 15002d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat if (code == VoldResponseCode.OpFailedStorageNotFound) { 15012d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat throw new IllegalArgumentException(String.format("Container '%s' not found", id)); 150222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else { 15032d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat throw new IllegalStateException(String.format("Unexpected response code %d", code)); 150422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 150522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 150622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 1507e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu 1508e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu public void finishMediaUpdate() { 1509e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE); 1510e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu } 151102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1512a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) { 1513a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (callerUid == android.os.Process.SYSTEM_UID) { 1514a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return true; 1515a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1516a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 151702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (packageName == null) { 151802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return false; 151902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 152002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 152102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root final int packageUid = mPms.getPackageUid(packageName); 152202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 152302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (DEBUG_OBB) { 152402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root Slog.d(TAG, "packageName = " + packageName + ", packageUid = " + 152502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root packageUid + ", callerUid = " + callerUid); 152602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 152702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 152802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return callerUid == packageUid; 152902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 153002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 153102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root public String getMountedObbPath(String filename) { 1532af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (filename == null) { 1533af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalArgumentException("filename cannot be null"); 1534af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1535af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 153602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root waitForReady(); 153702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root warnOnNotMounted(); 153802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 153902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root try { 154002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root ArrayList<String> rsp = mConnector.doCommand(String.format("obb path %s", filename)); 154102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root String []tok = rsp.get(0).split(" "); 154202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root int code = Integer.parseInt(tok[0]); 154302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (code != VoldResponseCode.AsecPathResult) { 154402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root throw new IllegalStateException(String.format("Unexpected response code %d", code)); 154502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 154602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return tok[1]; 154702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } catch (NativeDaemonConnectorException e) { 154802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root int code = e.getCode(); 154902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (code == VoldResponseCode.OpFailedStorageNotFound) { 1550a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return null; 155102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } else { 155202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root throw new IllegalStateException(String.format("Unexpected response code %d", code)); 155302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 155402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 155502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 155602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 155702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root public boolean isObbMounted(String filename) { 1558af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (filename == null) { 1559af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalArgumentException("filename cannot be null"); 1560af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1561af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1562a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root synchronized (mObbMounts) { 1563af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return mObbPathToStateMap.containsKey(filename); 1564a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1565a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1566a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1567af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root public void mountObb(String filename, String key, IObbActionListener token, int nonce) 1568735de3b38abbd6564082a819377673ee593744a6Kenny Root throws RemoteException { 1569f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root if (filename == null) { 1570f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root throw new IllegalArgumentException("filename cannot be null"); 157102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 157202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1573af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (token == null) { 1574af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalArgumentException("token cannot be null"); 15752942391801b79816c5eb77d7ac94c4a65f26af48Kenny Root } 1576735de3b38abbd6564082a819377673ee593744a6Kenny Root 1577af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final int callerUid = Binder.getCallingUid(); 1578af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbState obbState = new ObbState(filename, callerUid, token, nonce); 1579af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbAction action = new MountObbAction(obbState, key); 1580a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 1581a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1582a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1583a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Send to OBB handler: " + action.toString()); 158402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 158502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1586af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root public void unmountObb(String filename, boolean force, IObbActionListener token, int nonce) 1587af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throws RemoteException { 1588f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root if (filename == null) { 1589f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root throw new IllegalArgumentException("filename cannot be null"); 159002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 159102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1592af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final int callerUid = Binder.getCallingUid(); 1593af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbState obbState = new ObbState(filename, callerUid, token, nonce); 1594af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbAction action = new UnmountObbAction(obbState, force); 1595a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 1596a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1597a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1598a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Send to OBB handler: " + action.toString()); 1599a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 160002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1601af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private void addObbStateLocked(ObbState obbState) throws RemoteException { 1602af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IBinder binder = obbState.getBinder(); 1603af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root List<ObbState> obbStates = mObbMounts.get(binder); 16045919ac6b4188285324646772501ef4b97b353cf4Kenny Root 1605af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates == null) { 1606af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates = new ArrayList<ObbState>(); 1607af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.put(binder, obbStates); 1608af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 1609af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root for (final ObbState o : obbStates) { 1610af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (o.filename.equals(obbState.filename)) { 1611af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalStateException("Attempt to add ObbState twice. " 1612af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + "This indicates an error in the MountService logic."); 16135919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 16145919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 161502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 161602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1617af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates.add(obbState); 1618af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 1619af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState.link(); 1620af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (RemoteException e) { 1621af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root /* 1622af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * The binder died before we could link it, so clean up our state 1623af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * and return failure. 1624af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root */ 1625af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates.remove(obbState); 1626af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.isEmpty()) { 1627af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.remove(binder); 162805105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 16295919ac6b4188285324646772501ef4b97b353cf4Kenny Root 1630af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Rethrow the error so mountObb can get it 1631af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw e; 163202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 1633af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1634af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbPathToStateMap.put(obbState.filename, obbState); 1635a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 163602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1637af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private void removeObbStateLocked(ObbState obbState) { 1638af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IBinder binder = obbState.getBinder(); 1639af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStates = mObbMounts.get(binder); 1640af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates != null) { 1641af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.remove(obbState)) { 1642af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState.unlink(); 1643af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1644af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.isEmpty()) { 1645af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.remove(binder); 1646af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 164738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 1648af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1649af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbPathToStateMap.remove(obbState.filename); 165038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 165138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 1652a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private class ObbActionHandler extends Handler { 1653a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean mBound = false; 1654480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root private final List<ObbAction> mActions = new LinkedList<ObbAction>(); 1655a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1656a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbActionHandler(Looper l) { 1657a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(l); 1658a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1659a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1660a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 1661a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleMessage(Message msg) { 1662a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root switch (msg.what) { 1663a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_RUN_ACTION: { 1664480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root final ObbAction action = (ObbAction) msg.obj; 1665a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1666a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1667a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString()); 1668a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1669a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // If a bind was already initiated we don't really 1670a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // need to do anything. The pending install 1671a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // will be processed later on. 1672a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!mBound) { 1673a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // If this is the only one pending we might 1674a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // have to bind to the service again. 1675a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!connectToService()) { 1676a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Failed to bind to media container service"); 1677a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 1678a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return; 1679a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1680a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1681735de3b38abbd6564082a819377673ee593744a6Kenny Root 1682735de3b38abbd6564082a819377673ee593744a6Kenny Root mActions.add(action); 1683a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 1684a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1685a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_BOUND: { 1686a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1687a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_BOUND"); 1688a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (msg.obj != null) { 1689a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContainerService = (IMediaContainerService) msg.obj; 1690a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1691a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mContainerService == null) { 1692a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Something seriously wrong. Bail out 1693a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Cannot bind to media container service"); 1694a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root for (ObbAction action : mActions) { 1695a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Indicate service bind error 1696a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 1697a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1698a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.clear(); 1699a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else if (mActions.size() > 0) { 1700480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root final ObbAction action = mActions.get(0); 1701a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (action != null) { 1702a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.execute(this); 1703a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1704a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 1705a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Should never happen ideally. 1706a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.w(TAG, "Empty queue"); 1707a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1708a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 1709a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1710a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_RECONNECT: { 1711a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1712a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_RECONNECT"); 1713a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() > 0) { 1714a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mBound) { 1715a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root disconnectService(); 1716a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1717a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!connectToService()) { 1718a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Failed to bind to media container service"); 1719a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root for (ObbAction action : mActions) { 1720a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Indicate service bind error 1721a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 1722a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1723a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.clear(); 1724a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1725a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1726a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 1727a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1728a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_UNBIND: { 1729a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1730a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_UNBIND"); 1731a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1732a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Delete pending install 1733a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() > 0) { 1734a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.remove(0); 1735a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1736a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() == 0) { 1737a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mBound) { 1738a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root disconnectService(); 1739a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1740a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 1741a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // There are more pending requests in queue. 1742a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Just post MCS_BOUND message to trigger processing 1743a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // of next pending install. 1744a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND); 1745a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1746a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 1747a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1748af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root case OBB_FLUSH_MOUNT_STATE: { 1749af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final String path = (String) msg.obj; 1750af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1751af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 1752af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.i(TAG, "Flushing all OBB state for path " + path); 1753af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1754af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 1755af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>(); 1756af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1757af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Iterator<Entry<String, ObbState>> i = 1758af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbPathToStateMap.entrySet().iterator(); 1759af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (i.hasNext()) { 1760af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Entry<String, ObbState> obbEntry = i.next(); 1761af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1762af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root /* 1763af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * If this entry's source file is in the volume path 1764af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * that got unmounted, remove it because it's no 1765af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * longer valid. 1766af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root */ 1767af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbEntry.getKey().startsWith(path)) { 1768af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStatesToRemove.add(obbEntry.getValue()); 1769af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1770af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1771af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1772af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root for (final ObbState obbState : obbStatesToRemove) { 1773af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 1774af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.i(TAG, "Removing state for " + obbState.filename); 1775af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1776af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root removeObbStateLocked(obbState); 1777af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1778af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 1779af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState.token.onObbResult(obbState.filename, obbState.nonce, 1780af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root OnObbStateChangeListener.UNMOUNTED); 1781af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (RemoteException e) { 1782af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.i(TAG, "Couldn't send unmount notification for OBB: " 1783af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + obbState.filename); 1784af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1785af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1786af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1787af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root break; 1788af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 178902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 179002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 179102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1792a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean connectToService() { 1793a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1794a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Trying to bind to DefaultContainerService"); 1795a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1796a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); 1797a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) { 1798a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mBound = true; 1799a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return true; 180002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 1801a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return false; 1802a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1803a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1804a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private void disconnectService() { 1805a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContainerService = null; 1806a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mBound = false; 1807a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContext.unbindService(mDefContainerConn); 180802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 180902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 181002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1811a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root abstract class ObbAction { 1812a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int MAX_RETRIES = 3; 1813a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private int mRetries; 181402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1815a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbState mObbState; 1816a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1817a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbAction(ObbState obbState) { 1818a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbState = obbState; 181902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 182002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1821a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void execute(ObbActionHandler handler) { 1822a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root try { 1823a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1824a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Starting to execute action: " + this.toString()); 1825a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mRetries++; 1826a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mRetries > MAX_RETRIES) { 1827a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); 1828480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 1829a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleError(); 1830a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return; 1831a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 1832a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleExecute(); 1833a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1834a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Posting install MCS_UNBIND"); 1835a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 1836a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1837a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } catch (RemoteException e) { 1838a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1839a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Posting install MCS_RECONNECT"); 1840a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT); 1841a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } catch (Exception e) { 1842a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1843a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.d(TAG, "Error handling OBB action", e); 1844a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleError(); 184517eb6fb07cc6965f09c51adc70b3c291f57a784aKenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 184602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 1847a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 184802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 184905105f7abe02b2dff91d6260b3628c8b97816babKenny Root abstract void handleExecute() throws RemoteException, IOException; 1850a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root abstract void handleError(); 185138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 185238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root protected ObbInfo getObbInfo() throws IOException { 185338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root ObbInfo obbInfo; 185438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root try { 185538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root obbInfo = mContainerService.getObbInfo(mObbState.filename); 185638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } catch (RemoteException e) { 185738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for " 185838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root + mObbState.filename); 185938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root obbInfo = null; 186038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 186138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root if (obbInfo == null) { 186238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root throw new IOException("Couldn't read OBB file: " + mObbState.filename); 186338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 186438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return obbInfo; 186538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 186638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 1867af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root protected void sendNewStatusOrIgnore(int status) { 1868af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (mObbState == null || mObbState.token == null) { 1869af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 1870af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1871af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 187238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root try { 1873af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbState.token.onObbResult(mObbState.filename, mObbState.nonce, status); 187438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } catch (RemoteException e) { 187538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged"); 187638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 187738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 1878a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1879a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1880a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class MountObbAction extends ObbAction { 1881a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private String mKey; 1882a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1883a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root MountObbAction(ObbState obbState, String key) { 1884a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(obbState); 1885a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mKey = key; 1886a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1887a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1888735de3b38abbd6564082a819377673ee593744a6Kenny Root public void handleExecute() throws IOException, RemoteException { 1889af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root waitForReady(); 1890af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root warnOnNotMounted(); 1891af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 189238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root final ObbInfo obbInfo = getObbInfo(); 189338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 1894af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mObbState.callerUid)) { 1895af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename 1896af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + " which is owned by " + obbInfo.packageName); 1897af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); 1898af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 1899af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1900af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1901af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final boolean isMounted; 1902af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 1903af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root isMounted = mObbPathToStateMap.containsKey(obbInfo.filename); 1904af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1905af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (isMounted) { 1906af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename); 1907af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED); 1908af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 1909af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1910af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 191138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root /* 1912af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * The filename passed in might not be the canonical name, so just 1913af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * set the filename to the canonicalized version. 191438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root */ 1915af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbState.filename = obbInfo.filename; 191638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 1917af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final String hashedKey; 1918af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (mKey == null) { 1919af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root hashedKey = "none"; 1920af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 1921af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 19223b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 19233b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 19243b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt, 19253b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE); 19263b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root SecretKey key = factory.generateSecret(ks); 19273b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root BigInteger bi = new BigInteger(key.getEncoded()); 19283b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root hashedKey = bi.toString(16); 1929af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NoSuchAlgorithmException e) { 19303b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root Slog.e(TAG, "Could not load PBKDF2 algorithm", e); 19313b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 19323b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root return; 19333b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root } catch (InvalidKeySpecException e) { 19343b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e); 19353b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 1936af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 193738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 1938a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1939a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1940af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int rc = StorageResultCode.OperationSucceeded; 1941af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root String cmd = String.format("obb mount %s %s %d", mObbState.filename, hashedKey, 1942af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbState.callerUid); 1943af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 1944af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mConnector.doCommand(cmd); 1945af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NativeDaemonConnectorException e) { 1946af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int code = e.getCode(); 1947af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (code != VoldResponseCode.OpFailedStorageBusy) { 1948af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedInternalError; 1949a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1950af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1951a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1952af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (rc == StorageResultCode.OperationSucceeded) { 1953af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 1954af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.d(TAG, "Successfully mounted OBB " + mObbState.filename); 195538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 1956af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 1957af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root addObbStateLocked(mObbState); 1958a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 195938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 1960af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED); 196102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } else { 196205105f7abe02b2dff91d6260b3628c8b97816babKenny Root Slog.e(TAG, "Couldn't mount OBB file: " + rc); 1963a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1964af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT); 196502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 196602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 196702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1968a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleError() { 1969af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 197002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 1971a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1972a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 1973a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public String toString() { 1974a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root StringBuilder sb = new StringBuilder(); 1975a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("MountObbAction{"); 1976a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("filename="); 1977a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.filename); 1978a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",callerUid="); 1979a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.callerUid); 1980a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",token="); 1981a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.token != null ? mObbState.token.toString() : "NULL"); 1982af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sb.append(",binder="); 1983af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sb.append(mObbState.token != null ? mObbState.getBinder().toString() : "null"); 1984a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append('}'); 1985a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return sb.toString(); 1986a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1987a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1988a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1989a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class UnmountObbAction extends ObbAction { 1990a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean mForceUnmount; 1991a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1992a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root UnmountObbAction(ObbState obbState, boolean force) { 1993a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(obbState); 1994a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mForceUnmount = force; 1995a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1996a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 199738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root public void handleExecute() throws IOException { 1998af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root waitForReady(); 1999af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root warnOnNotMounted(); 2000af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 200138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root final ObbInfo obbInfo = getObbInfo(); 2002a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2003af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbState obbState; 200438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root synchronized (mObbMounts) { 2005af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState = mObbPathToStateMap.get(obbInfo.filename); 2006af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 200738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2008af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbState == null) { 2009af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED); 2010af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2011a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2012a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2013af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbState.callerUid != mObbState.callerUid) { 2014af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Permission denied attempting to unmount OBB " + obbInfo.filename 2015af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + " (owned by " + obbInfo.packageName + ")"); 2016af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); 2017af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2018af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2019a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2020af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbState.filename = obbInfo.filename; 202138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2022af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int rc = StorageResultCode.OperationSucceeded; 2023af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root String cmd = String.format("obb unmount %s%s", mObbState.filename, 2024af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root (mForceUnmount ? " force" : "")); 2025af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 2026af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mConnector.doCommand(cmd); 2027af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NativeDaemonConnectorException e) { 2028af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int code = e.getCode(); 2029af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (code == VoldResponseCode.OpFailedStorageBusy) { 2030af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedStorageBusy; 2031af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else if (code == VoldResponseCode.OpFailedStorageNotFound) { 2032af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // If it's not mounted then we've already won. 2033af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationSucceeded; 2034af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 2035af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedInternalError; 2036a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2037a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 203838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2039af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (rc == StorageResultCode.OperationSucceeded) { 2040af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 2041af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root removeObbStateLocked(obbState); 2042af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 204338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2044af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED); 204538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } else { 2046af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Could not mount OBB: " + mObbState.filename); 2047af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT); 204838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2049a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2050a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2051a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleError() { 2052af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 2053a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2054a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2055a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 2056a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public String toString() { 2057a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root StringBuilder sb = new StringBuilder(); 2058a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("UnmountObbAction{"); 2059a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("filename="); 2060a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.filename != null ? mObbState.filename : "null"); 2061a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",force="); 2062a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mForceUnmount); 2063a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",callerUid="); 2064a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.callerUid); 2065a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",token="); 2066a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.token != null ? mObbState.token.toString() : "null"); 2067735de3b38abbd6564082a819377673ee593744a6Kenny Root sb.append(",binder="); 2068af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sb.append(mObbState.token != null ? mObbState.getBinder().toString() : "null"); 2069a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append('}'); 2070a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return sb.toString(); 2071a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 207202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 207338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 207438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root @Override 207538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 207638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { 207738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root pw.println("Permission Denial: can't dump ActivityManager from from pid=" 207838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() 207938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root + " without permission " + android.Manifest.permission.DUMP); 208038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return; 208138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 208238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 208338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root synchronized (mObbMounts) { 2084af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(" mObbMounts:"); 208538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2086af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet().iterator(); 2087af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (binders.hasNext()) { 2088af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Entry<IBinder, List<ObbState>> e = binders.next(); 2089af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" Key="); pw.println(e.getKey().toString()); 2090af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStates = e.getValue(); 209138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root for (final ObbState obbState : obbStates) { 2092af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" "); pw.println(obbState.toString()); 209338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 209438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2095af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2096af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(""); 2097af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(" mObbPathToStateMap:"); 2098af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator(); 2099af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (maps.hasNext()) { 2100af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Entry<String, ObbState> e = maps.next(); 2101af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" "); pw.print(e.getKey()); 2102af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" -> "); pw.println(e.getValue().toString()); 2103af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 210438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 210538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 21069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 21079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2108