MountService.java revision f097fc2fee57183508558acbca1f8742fb55615a
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 228888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parksimport android.Manifest; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver; 24a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ComponentName; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter; 28a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ServiceConnection; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager; 3002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.content.res.ObbInfo; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri; 3202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.os.Binder; 33a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.Environment; 34c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Handler; 355f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.HandlerThread; 36a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.IBinder; 375f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.Looper; 38c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Message; 394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehatimport android.os.RemoteException; 40fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapuimport android.os.ServiceManager; 41207e538350665cea00e1aa70b8094beca4a34e45San Mehatimport android.os.SystemClock; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties; 43a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountService; 44a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountServiceListener; 45a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountShutdownObserver; 46a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IObbActionListener; 47af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Rootimport android.os.storage.OnObbStateChangeListener; 48a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.StorageResultCode; 49f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parksimport android.text.TextUtils; 50a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehatimport android.util.Slog; 51a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 5238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.FileDescriptor; 5305105f7abe02b2dff91d6260b3628c8b97816babKenny Rootimport java.io.IOException; 5438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.PrintWriter; 553b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.math.BigInteger; 56735de3b38abbd6564082a819377673ee593744a6Kenny Rootimport java.security.NoSuchAlgorithmException; 573b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.InvalidKeySpecException; 583b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.KeySpec; 5922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehatimport java.util.ArrayList; 60a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.HashMap; 616cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehatimport java.util.HashSet; 6238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Iterator; 63a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.LinkedList; 64a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.List; 65a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.Map; 6638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Map.Entry; 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 683b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKey; 693b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKeyFactory; 703b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.spec.PBEKeySpec; 713b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 73b104340496e3a531e26c8f428c808eca0e039f50San Mehat * MountService implements back-end services for platform storage 74b104340496e3a531e26c8f428c808eca0e039f50San Mehat * management. 75b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @hide - Applications should use android.os.storage.StorageManager 76b104340496e3a531e26c8f428c808eca0e039f50San Mehat * to access the MountService. 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 785af0b916f850486cff4797355bf9e7dc3352fe00Jason parksclass MountService extends IMountService.Stub implements INativeDaemonConnectorCallbacks { 795af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 80b104340496e3a531e26c8f428c808eca0e039f50San Mehat private static final boolean LOCAL_LOGD = false; 818a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu private static final boolean DEBUG_UNMOUNT = false; 828a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu private static final boolean DEBUG_EVENTS = false; 83b7db2726e91f1d9480359d0f83b9cb7769906b34Kenny Root private static final boolean DEBUG_OBB = false; 8402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String TAG = "MountService"; 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 87305bcbf0c961840c4505770d084a1caacc074dbbKenny Root private static final String VOLD_TAG = "VoldConnector"; 88305bcbf0c961840c4505770d084a1caacc074dbbKenny Root 894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Internal vold volume state constants 914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 927fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat class VolumeState { 937fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Init = -1; 947fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int NoMedia = 0; 957fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Idle = 1; 967fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Pending = 2; 977fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Checking = 3; 987fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Mounted = 4; 997fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Unmounting = 5; 1007fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Formatting = 6; 1017fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Shared = 7; 1027fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int SharedMnt = 8; 1037fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 1047fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 1054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Internal vold response code constants 1074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 10822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat class VoldResponseCode { 1094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 100 series - Requestion action was initiated; expect another reply 1114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * before proceeding with a new command. 1124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 11322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeListResult = 110; 11422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int AsecListResult = 111; 115c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat public static final int StorageUsersListResult = 112; 11622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 200 series - Requestion action has been successfully completed. 1194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 1204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int ShareStatusResult = 210; 12122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int AsecPathResult = 211; 1224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int ShareEnabledResult = 212; 12322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 400 series - Command was accepted, but the requested action 1264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * did not take place. 1274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 1284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedNoMedia = 401; 1294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedMediaBlank = 402; 1304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedMediaCorrupt = 403; 1314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedVolNotMounted = 404; 132d970998b0d489774ad1c5b94b47d233912f00214San Mehat public static final int OpFailedStorageBusy = 405; 1332d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat public static final int OpFailedStorageNotFound = 406; 1344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 600 series - Unsolicited broadcasts. 1374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 13822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeStateChange = 605; 13922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int ShareAvailabilityChange = 620; 14022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeDiskInserted = 630; 14122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeDiskRemoved = 631; 14222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeBadRemoval = 632; 14322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 14422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private Context mContext; 1464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private NativeDaemonConnector mConnector; 147f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood private final HashMap<String, String> mVolumeStates = new HashMap<String, String>(); 148f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood private String mExternalStoragePath; 1494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private PackageManagerService mPms; 1504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private boolean mUmsEnabling; 1510eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Used as a lock for methods that register/unregister listeners. 1520eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu final private ArrayList<MountServiceBinderListener> mListeners = 1530eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu new ArrayList<MountServiceBinderListener>(); 1546a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private boolean mBooted = false; 1556a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private boolean mReady = false; 1566a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private boolean mSendUmsConnectedOnBoot = false; 15703559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood // true if we should fake MEDIA_MOUNTED state for external storage 15803559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood private boolean mEmulateExternalStorage = false; 159fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapu 1606cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat /** 1616cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat * Private hash of currently mounted secure containers. 1620eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * Used as a lock in methods to manipulate secure containers. 1636cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat */ 1640eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu final private HashSet<String> mAsecMountSet = new HashSet<String>(); 1656cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 16602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root /** 1673b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * The size of the crypto algorithm key in bits for OBB files. Currently 1683b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * Twofish is used which takes 128-bit keys. 1693b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root */ 1703b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128; 1713b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 1723b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root /** 1733b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * The number of times to run SHA1 in the PBKDF2 function for OBB files. 1743b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root * 1024 is reasonably secure and not too slow. 1753b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root */ 1763b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root private static final int PBKDF2_HASH_ROUNDS = 1024; 1773b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 1783b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root /** 179a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * Mounted OBB tracking information. Used to track the current state of all 180a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * OBBs. 181a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root */ 182735de3b38abbd6564082a819377673ee593744a6Kenny Root final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>(); 183a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>(); 184a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 185a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class ObbState implements IBinder.DeathRecipient { 186af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root public ObbState(String filename, int callerUid, IObbActionListener token, int nonce) 187735de3b38abbd6564082a819377673ee593744a6Kenny Root throws RemoteException { 188a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root this.filename = filename; 189a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root this.callerUid = callerUid; 190af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root this.token = token; 191af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root this.nonce = nonce; 192a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 193a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 194a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // OBB source filename 195af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root String filename; 196a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 197a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Binder.callingUid() 19805105f7abe02b2dff91d6260b3628c8b97816babKenny Root final public int callerUid; 199a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 200af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Token of remote Binder caller 201af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IObbActionListener token; 202af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 203af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Identifier to pass back to the token 204af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final int nonce; 205a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 206735de3b38abbd6564082a819377673ee593744a6Kenny Root public IBinder getBinder() { 207735de3b38abbd6564082a819377673ee593744a6Kenny Root return token.asBinder(); 208735de3b38abbd6564082a819377673ee593744a6Kenny Root } 209735de3b38abbd6564082a819377673ee593744a6Kenny Root 210a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 211a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void binderDied() { 212a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbAction action = new UnmountObbAction(this, true); 213a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 214735de3b38abbd6564082a819377673ee593744a6Kenny Root } 215a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2165919ac6b4188285324646772501ef4b97b353cf4Kenny Root public void link() throws RemoteException { 2175919ac6b4188285324646772501ef4b97b353cf4Kenny Root getBinder().linkToDeath(this, 0); 2185919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 2195919ac6b4188285324646772501ef4b97b353cf4Kenny Root 2205919ac6b4188285324646772501ef4b97b353cf4Kenny Root public void unlink() { 221735de3b38abbd6564082a819377673ee593744a6Kenny Root getBinder().unlinkToDeath(this, 0); 222a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 22338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 22438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root @Override 22538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root public String toString() { 22638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root StringBuilder sb = new StringBuilder("ObbState{"); 22738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append("filename="); 22838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(filename); 22938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(",token="); 23038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(token.toString()); 23138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(",callerUid="); 23238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append(callerUid); 23338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root sb.append('}'); 23438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return sb.toString(); 23538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 236a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 237a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 238a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // OBB Action Handler 239a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private ObbActionHandler mObbActionHandler; 240a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 241a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // OBB action handler messages 242a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_RUN_ACTION = 1; 243a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_BOUND = 2; 244a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_UNBIND = 3; 245a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int OBB_MCS_RECONNECT = 4; 246af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private static final int OBB_FLUSH_MOUNT_STATE = 5; 247a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 248a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root /* 249a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root * Default Container Service information 25002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root */ 251a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName( 252a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService"); 253a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 254a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection(); 255a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 256a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class DefaultContainerConnection implements ServiceConnection { 257a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void onServiceConnected(ComponentName name, IBinder service) { 258a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 259a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "onServiceConnected"); 260a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service); 261a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs)); 262a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 263a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 264a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void onServiceDisconnected(ComponentName name) { 265a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 266a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "onServiceDisconnected"); 267a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 268a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root }; 269a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 270a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Used in the ObbActionHandler 271a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private IMediaContainerService mContainerService = null; 27202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 27302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root // Handler messages 274c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_PM_UPDATE = 1; 275c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_PM_DONE = 2; 276c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_MS = 3; 277c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int RETRY_UNMOUNT_DELAY = 30; // in ms 278c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int MAX_UNMOUNT_RETRIES = 4; 279c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 280c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu class UnmountCallBack { 28105105f7abe02b2dff91d6260b3628c8b97816babKenny Root final String path; 28205105f7abe02b2dff91d6260b3628c8b97816babKenny Root final boolean force; 283c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu int retries; 284c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 285c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack(String path, boolean force) { 286c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu retries = 0; 287c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu this.path = path; 288c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu this.force = force; 289c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 2900eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 2910eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu void handleFinished() { 292a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path); 2930eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doUnmountVolume(path, true); 2940eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 2950eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 2960eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 2970eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu class UmsEnableCallBack extends UnmountCallBack { 29805105f7abe02b2dff91d6260b3628c8b97816babKenny Root final String method; 2990eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3000eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu UmsEnableCallBack(String path, String method, boolean force) { 3010eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu super(path, force); 3020eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu this.method = method; 3030eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 3040eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 3050eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu @Override 3060eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu void handleFinished() { 3070eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu super.handleFinished(); 3080eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doShareUnshareVolume(path, method, true); 3090eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 310c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 311c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 3126ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu class ShutdownCallBack extends UnmountCallBack { 3136ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu IMountShutdownObserver observer; 3146ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu ShutdownCallBack(String path, IMountShutdownObserver observer) { 3156ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu super(path, true); 3166ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu this.observer = observer; 3176ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3186ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3196ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu @Override 3206ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu void handleFinished() { 3216ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int ret = doUnmountVolume(path, true); 3226ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (observer != null) { 3236ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu try { 3246ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu observer.onShutDownComplete(ret); 3256ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } catch (RemoteException e) { 326a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "RemoteException when shutting down"); 3276ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3286ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3296ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3306ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3316ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3325f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler class MountServiceHandler extends Handler { 333c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>(); 334e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu boolean mUpdatingStatus = false; 3356ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 3365f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler MountServiceHandler(Looper l) { 3375f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler super(l); 3385f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler } 3395f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler 3405af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 341c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu public void handleMessage(Message msg) { 342c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu switch (msg.what) { 343c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_PM_UPDATE: { 344a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_UPDATE"); 345c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = (UnmountCallBack) msg.obj; 346c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu mForceUnmounts.add(ucb); 347a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, " registered = " + mUpdatingStatus); 3486ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Register only if needed. 349e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu if (!mUpdatingStatus) { 350a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Updating external media status on PackageManager"); 351e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mUpdatingStatus = true; 352e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(false, true); 353c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 354c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 355c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 356c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_PM_DONE: { 357a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_DONE"); 358a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Updated status. Processing requests"); 359e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mUpdatingStatus = false; 3606ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int size = mForceUnmounts.size(); 3616ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int sizeArr[] = new int[size]; 3626ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int sizeArrN = 0; 3637af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Kill processes holding references first 3647af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ActivityManagerService ams = (ActivityManagerService) 3657af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ServiceManager.getService("activity"); 3666ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu for (int i = 0; i < size; i++) { 3676ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu UnmountCallBack ucb = mForceUnmounts.get(i); 3686ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu String path = ucb.path; 3696ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu boolean done = false; 3706ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (!ucb.force) { 371c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu done = true; 372c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } else { 3736ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int pids[] = getStorageUsers(path); 3746ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (pids == null || pids.length == 0) { 3756ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu done = true; 3766ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } else { 3776ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Eliminate system process here? 378648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn ams.killPids(pids, "unmount media", true); 3797af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Confirm if file references have been freed. 3807af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu pids = getStorageUsers(path); 3817af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu if (pids == null || pids.length == 0) { 3827af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu done = true; 383c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 384c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 385c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 3867af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) { 3877af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Retry again 3887af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu Slog.i(TAG, "Retrying to kill storage users again"); 3897af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.sendMessageDelayed( 3907af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.obtainMessage(H_UNMOUNT_PM_DONE, 3917af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ucb.retries++), 3927af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu RETRY_UNMOUNT_DELAY); 393c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } else { 3946ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (ucb.retries >= MAX_UNMOUNT_RETRIES) { 3957af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu Slog.i(TAG, "Failed to unmount media inspite of " + 3967af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu MAX_UNMOUNT_RETRIES + " retries. Forcibly killing processes now"); 3976ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 3987af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu sizeArr[sizeArrN++] = i; 3997af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS, 4007af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ucb)); 401c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 402c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 4036ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Remove already processed elements from list. 4046ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu for (int i = (sizeArrN-1); i >= 0; i--) { 4056ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu mForceUnmounts.remove(sizeArr[i]); 4066ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 407c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 408c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 409c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_MS : { 410a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_MS"); 411c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = (UnmountCallBack) msg.obj; 4120eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu ucb.handleFinished(); 413c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 414c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 415c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 416c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 417c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu }; 4185f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler final private HandlerThread mHandlerThread; 4195f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler final private Handler mHandler; 420c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 421207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void waitForReady() { 422207e538350665cea00e1aa70b8094beca4a34e45San Mehat while (mReady == false) { 423207e538350665cea00e1aa70b8094beca4a34e45San Mehat for (int retries = 5; retries > 0; retries--) { 424207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (mReady) { 425207e538350665cea00e1aa70b8094beca4a34e45San Mehat return; 426207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 427207e538350665cea00e1aa70b8094beca4a34e45San Mehat SystemClock.sleep(1000); 428207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 429a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Waiting too long for mReady!"); 430207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 4311f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 43202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 433207e538350665cea00e1aa70b8094beca4a34e45San Mehat private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 4345af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onReceive(Context context, Intent intent) { 43691c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat String action = intent.getAction(); 43791c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 43891c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { 439207e538350665cea00e1aa70b8094beca4a34e45San Mehat mBooted = true; 44022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 441c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen /* 442c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * In the simulator, we need to broadcast a volume mounted event 443c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * to make the media scanner run. 444c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen */ 445c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen if ("simulator".equals(SystemProperties.get("ro.product.device"))) { 446c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen notifyVolumeStateChange(null, "/sdcard", VolumeState.NoMedia, VolumeState.Mounted); 447c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen return; 448c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen } 449fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat new Thread() { 4505af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 451fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat public void run() { 452fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat try { 453f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood synchronized (mVolumeStates) { 454f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood for (String path : mVolumeStates.keySet()) { 455f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood String state = mVolumeStates.get(path); 456f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood 457f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood if (state.equals(Environment.MEDIA_UNMOUNTED)) { 458f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood int rc = doMountVolume(path); 459f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood if (rc != StorageResultCode.OperationSucceeded) { 460f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood Slog.e(TAG, String.format("Boot-time mount failed (%d)", 461f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood rc)); 462f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood } 463f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood } else if (state.equals(Environment.MEDIA_SHARED)) { 464f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood /* 465f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood * Bootstrap UMS enabled state since vold indicates 466f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood * the volume is shared (runtime restart while ums enabled) 467f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood */ 468f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood notifyVolumeStateChange(null, path, VolumeState.NoMedia, 469f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood VolumeState.Shared); 470f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood } 471fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } 472fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } 4736a254403235196692b1769d2fe281b0852c0cc25San Mehat 4746a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat /* 4756a254403235196692b1769d2fe281b0852c0cc25San Mehat * If UMS was connected on boot, send the connected event 4766a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat * now that we're up. 4776a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat */ 4786a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat if (mSendUmsConnectedOnBoot) { 4796a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat sendUmsIntent(true); 4806a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat mSendUmsConnectedOnBoot = false; 4816a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } 482fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } catch (Exception ex) { 483a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Boot-time mount exception", ex); 484fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } 485207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 486fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat }.start(); 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private final class MountServiceBinderListener implements IBinder.DeathRecipient { 4924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final IMountServiceListener mListener; 49391c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 4944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener(IMountServiceListener listener) { 4954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListener = listener; 49602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 49791c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 49891c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 4994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void binderDied() { 500a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!"); 501a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root synchronized (mListeners) { 5024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(this); 5034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListener.asBinder().unlinkToDeath(this, 0); 50491c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 50591c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 50691c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 50791c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 5080eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private void doShareUnshareVolume(String path, String method, boolean enable) { 5094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat // TODO: Add support for multiple share methods 5104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!method.equals("ums")) { 5114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new IllegalArgumentException(String.format("Method %s not supported", method)); 5127fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 5154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(String.format( 5164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat "volume %sshare %s %s", (enable ? "" : "un"), path, method)); 5174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 518a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to share/unshare", e); 51922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 522207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void updatePublicVolumeState(String path, String state) { 523f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood String oldState; 524f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood synchronized(mVolumeStates) { 525f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood oldState = mVolumeStates.put(path, state); 5267fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 527f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood if (state.equals(oldState)) { 528f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood Slog.w(TAG, String.format("Duplicate state transition (%s -> %s) for %s", 529f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood state, state, path)); 530b104340496e3a531e26c8f428c808eca0e039f50San Mehat return; 531b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 532af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 533f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood Slog.d(TAG, "volume state changed for " + path + " (" + oldState + " -> " + state + ")"); 534f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood 535f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood if (path.equals(mExternalStoragePath)) { 536f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood // Update state on PackageManager, but only of real events 537f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood if (!mEmulateExternalStorage) { 538f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood if (Environment.MEDIA_UNMOUNTED.equals(state)) { 539f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood mPms.updateExternalMediaStatus(false, false); 540f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood 541f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood /* 542f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood * Some OBBs might have been unmounted when this volume was 543f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood * unmounted, so send a message to the handler to let it know to 544f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood * remove those from the list of mounted OBBS. 545f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood */ 546f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage( 547f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood OBB_FLUSH_MOUNT_STATE, path)); 548f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood } else if (Environment.MEDIA_MOUNTED.equals(state)) { 549f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood mPms.updateExternalMediaStatus(true, false); 550f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood } 55103559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood } 5528a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 5534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 5544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for (int i = mListeners.size() -1; i >= 0; i--) { 5554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = mListeners.get(i); 5564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 557b104340496e3a531e26c8f428c808eca0e039f50San Mehat bl.mListener.onStorageStateChanged(path, oldState, state); 5584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 559a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener dead"); 5604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(i); 5614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 562a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener failed", ex); 5634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 56822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat /** 56922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * 57022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * Callback from NativeDaemonConnector 57122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat */ 57222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public void onDaemonConnected() { 5735b77dab23469273d41f9c530d947ac055765e6eaSan Mehat /* 5745b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * Since we'll be calling back into the NativeDaemonConnector, 5755b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * we need to do our work in a new thread. 5765b77dab23469273d41f9c530d947ac055765e6eaSan Mehat */ 5777fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat new Thread() { 5785af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 5797fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public void run() { 5805b77dab23469273d41f9c530d947ac055765e6eaSan Mehat /** 5815b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * Determine media state and UMS detection status 5825b77dab23469273d41f9c530d947ac055765e6eaSan Mehat */ 5837fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat try { 5845b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String[] vols = mConnector.doListCommand( 5854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat "volume list", VoldResponseCode.VolumeListResult); 5865b77dab23469273d41f9c530d947ac055765e6eaSan Mehat for (String volstr : vols) { 5875b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String[] tok = volstr.split(" "); 5885b77dab23469273d41f9c530d947ac055765e6eaSan Mehat // FMT: <label> <mountpoint> <state> 589f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood String path = tok[1]; 590f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood String state = Environment.MEDIA_REMOVED; 591f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood 5925b77dab23469273d41f9c530d947ac055765e6eaSan Mehat int st = Integer.parseInt(tok[2]); 5935b77dab23469273d41f9c530d947ac055765e6eaSan Mehat if (st == VolumeState.NoMedia) { 5945b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_REMOVED; 5955b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Idle) { 596207e538350665cea00e1aa70b8094beca4a34e45San Mehat state = Environment.MEDIA_UNMOUNTED; 5975b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Mounted) { 5985b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_MOUNTED; 599a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Media already mounted on daemon connection"); 6005b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Shared) { 6015b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_SHARED; 602a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Media shared on daemon connection"); 6035b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else { 6045b77dab23469273d41f9c530d947ac055765e6eaSan Mehat throw new Exception(String.format("Unexpected state %d", st)); 6057fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 606f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood 607f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood if (state != null) { 608f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state); 609f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood updatePublicVolumeState(path, state); 610f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood } 611c2a39471642e31d7350910612e40d078b825173aSan Mehat } 6125b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } catch (Exception e) { 613a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Error processing initial volume state", e); 614f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood updatePublicVolumeState(mExternalStoragePath, Environment.MEDIA_REMOVED); 6157fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6167fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 6177fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat try { 618207e538350665cea00e1aa70b8094beca4a34e45San Mehat boolean avail = doGetShareMethodAvailable("ums"); 6197fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat notifyShareAvailabilityChange("ums", avail); 6207fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } catch (Exception ex) { 621a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Failed to get share availability"); 6227fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 623207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 6249ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks * Now that we've done our initialization, release 625207e538350665cea00e1aa70b8094beca4a34e45San Mehat * the hounds! 626207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 627207e538350665cea00e1aa70b8094beca4a34e45San Mehat mReady = true; 6287fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6297fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat }.start(); 6307fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6317fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 63222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat /** 63322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * Callback from NativeDaemonConnector 63422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat */ 63522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public boolean onEvent(int code, String raw, String[] cooked) { 6364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Intent in = null; 6374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 6388a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (DEBUG_EVENTS) { 6398a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu StringBuilder builder = new StringBuilder(); 6408a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append("onEvent::"); 6418a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" raw= " + raw); 6428a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (cooked != null) { 6438a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" cooked = " ); 6448a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu for (String str : cooked) { 6458a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" " + str); 6468a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 6478a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 648a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, builder.toString()); 6498a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 65022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat if (code == VoldResponseCode.VolumeStateChange) { 6514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 6524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * One of the volumes we're managing has changed state. 6534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Format: "NNN Volume <label> <path> state changed 6544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * from <old_#> (<old_str>) to <new_#> (<new_str>)" 6554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 65622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat notifyVolumeStateChange( 65722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat cooked[2], cooked[3], Integer.parseInt(cooked[7]), 65822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat Integer.parseInt(cooked[10])); 65922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else if (code == VoldResponseCode.ShareAvailabilityChange) { 66022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Share method <method> now <available|unavailable> 66122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat boolean avail = false; 66222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat if (cooked[5].equals("available")) { 66322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat avail = true; 66422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 66522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat notifyShareAvailabilityChange(cooked[3], avail); 6664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if ((code == VoldResponseCode.VolumeDiskInserted) || 6674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat (code == VoldResponseCode.VolumeDiskRemoved) || 6684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat (code == VoldResponseCode.VolumeBadRemoval)) { 66922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>) 67022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>) 67122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>) 6724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final String label = cooked[2]; 6734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final String path = cooked[3]; 6744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int major = -1; 6754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int minor = -1; 6764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 6774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 6784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String devComp = cooked[6].substring(1, cooked[6].length() -1); 6794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String[] devTok = devComp.split(":"); 6804270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat major = Integer.parseInt(devTok[0]); 6814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat minor = Integer.parseInt(devTok[1]); 6824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 683a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to parse major/minor", ex); 6844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 6864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (code == VoldResponseCode.VolumeDiskInserted) { 6874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat new Thread() { 6885af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 6894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void run() { 6904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 6914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int rc; 692b104340496e3a531e26c8f428c808eca0e039f50San Mehat if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { 693a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, String.format("Insertion mount failed (%d)", rc)); 6944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 696a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Failed to mount media on insertion", ex); 6974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat }.start(); 7004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (code == VoldResponseCode.VolumeDiskRemoved) { 7014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 7024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * This event gets trumped if we're already in BAD_REMOVAL state 7034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 7044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) { 7054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return true; 7064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 708a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first"); 7094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 7104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); 7114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 7124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 713a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed"); 7144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_REMOVED); 7154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_REMOVED, Uri.parse("file://" + path)); 7164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (code == VoldResponseCode.VolumeBadRemoval) { 717a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first"); 7184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 7194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 7204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); 7214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 7224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 723a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal"); 7244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL); 7254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL, Uri.parse("file://" + path)); 7264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else { 727a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Unknown code {%d}", code)); 7284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 72922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else { 73022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat return false; 73122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 7324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 7334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (in != null) { 7344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 7355f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler } 7365f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler return true; 73722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 73822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 739207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void notifyVolumeStateChange(String label, String path, int oldState, int newState) { 7404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String vs = getVolumeState(path); 741a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChanged::" + vs); 7424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 7434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Intent in = null; 7447fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 745bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood if (oldState == VolumeState.Shared && newState != oldState) { 746a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent"); 747bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_UNSHARED, 748bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood Uri.parse("file://" + path))); 749bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood } 750bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood 7517fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat if (newState == VolumeState.Init) { 7527fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.NoMedia) { 7537fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat // NoMedia is handled via Disk Remove events 7547fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Idle) { 7555fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat /* 7565fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or 7575fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat * if we're in the process of enabling UMS 7585fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat */ 7594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!vs.equals( 7604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Environment.MEDIA_BAD_REMOVAL) && !vs.equals( 7614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Environment.MEDIA_NOFS) && !vs.equals( 7620eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) { 763a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable"); 7644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 7654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); 7667fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 7677fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Pending) { 7687fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Checking) { 769a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking"); 7704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_CHECKING); 7714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_CHECKING, Uri.parse("file://" + path)); 7727fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Mounted) { 773a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted"); 7744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_MOUNTED); 7754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + path)); 7764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in.putExtra("read-only", false); 7777fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Unmounting) { 7784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_EJECT, Uri.parse("file://" + path)); 7797fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Formatting) { 7807fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Shared) { 781a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted"); 7824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 7834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 7844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); 7854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 7864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 787a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared"); 7884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_SHARED); 7894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_SHARED, Uri.parse("file://" + path)); 790a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent"); 7917fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.SharedMnt) { 792a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Live shared mounts not supported yet!"); 7934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return; 7947fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else { 795a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Unhandled VolumeState {" + newState + "}"); 7967fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 7977fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 7984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (in != null) { 7994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 803207e538350665cea00e1aa70b8094beca4a34e45San Mehat private boolean doGetShareMethodAvailable(String method) { 80485fb20665feadda526ad422c093b859e8c4d40bcKenny Root ArrayList<String> rsp; 805a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root try { 80685fb20665feadda526ad422c093b859e8c4d40bcKenny Root rsp = mConnector.doCommand("share status " + method); 807a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } catch (NativeDaemonConnectorException ex) { 808a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root Slog.e(TAG, "Failed to determine whether share method " + method + " is available."); 809a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return false; 810a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } 811207e538350665cea00e1aa70b8094beca4a34e45San Mehat 812207e538350665cea00e1aa70b8094beca4a34e45San Mehat for (String line : rsp) { 813a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root String[] tok = line.split(" "); 814a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root if (tok.length < 3) { 815a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root Slog.e(TAG, "Malformed response to share status " + method); 816a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return false; 817a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } 818a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root 819207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code; 820207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 821207e538350665cea00e1aa70b8094beca4a34e45San Mehat code = Integer.parseInt(tok[0]); 822207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NumberFormatException nfe) { 823a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Error parsing code %s", tok[0])); 824207e538350665cea00e1aa70b8094beca4a34e45San Mehat return false; 825207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 826207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.ShareStatusResult) { 827207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (tok[2].equals("available")) 828207e538350665cea00e1aa70b8094beca4a34e45San Mehat return true; 829207e538350665cea00e1aa70b8094beca4a34e45San Mehat return false; 830207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 831a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Unexpected response code %d", code)); 832207e538350665cea00e1aa70b8094beca4a34e45San Mehat return false; 833207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 834207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 835a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Got an empty response"); 836207e538350665cea00e1aa70b8094beca4a34e45San Mehat return false; 837207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 838207e538350665cea00e1aa70b8094beca4a34e45San Mehat 839207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doMountVolume(String path) { 840b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 841207e538350665cea00e1aa70b8094beca4a34e45San Mehat 842a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path); 843207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 844207e538350665cea00e1aa70b8094beca4a34e45San Mehat mConnector.doCommand(String.format("volume mount %s", path)); 845207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 846207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 847207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Mount failed for some reason 848207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 849207e538350665cea00e1aa70b8094beca4a34e45San Mehat Intent in = null; 850207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 851207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedNoMedia) { 852207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 853207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Attempt to mount but no media inserted 854207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 855b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedNoMedia; 856207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaBlank) { 857a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs"); 858207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 859207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Media is blank or does not contain a supported filesystem 860207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 861207e538350665cea00e1aa70b8094beca4a34e45San Mehat updatePublicVolumeState(path, Environment.MEDIA_NOFS); 862207e538350665cea00e1aa70b8094beca4a34e45San Mehat in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path)); 863b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedMediaBlank; 864207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { 865a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state media corrupt"); 866207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 867207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Volume consistency check failed 868207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 869207e538350665cea00e1aa70b8094beca4a34e45San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE); 870207e538350665cea00e1aa70b8094beca4a34e45San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path)); 871b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedMediaCorrupt; 872207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 873b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 874207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 875207e538350665cea00e1aa70b8094beca4a34e45San Mehat 876207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 877207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Send broadcast intent (if required for the failure) 878207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 879207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (in != null) { 880207e538350665cea00e1aa70b8094beca4a34e45San Mehat mContext.sendBroadcast(in); 881207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 882207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 883207e538350665cea00e1aa70b8094beca4a34e45San Mehat 884207e538350665cea00e1aa70b8094beca4a34e45San Mehat return rc; 885207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 886207e538350665cea00e1aa70b8094beca4a34e45San Mehat 887c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu /* 888c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * If force is not set, we do not unmount if there are 889c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * processes holding references to the volume about to be unmounted. 890c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * If force is set, all the processes holding references need to be 891c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * killed via the ActivityManager before actually unmounting the volume. 892c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * This might even take a while and might be retried after timed delays 893c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * to make sure we dont end up in an instable state and kill some core 894c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * processes. 895c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu */ 896d970998b0d489774ad1c5b94b47d233912f00214San Mehat private int doUnmountVolume(String path, boolean force) { 89759443a673a736978361dc341f41ce4e9dae053a0San Mehat if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) { 898207e538350665cea00e1aa70b8094beca4a34e45San Mehat return VoldResponseCode.OpFailedVolNotMounted; 899207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 900aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 901aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 902aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 903aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 904aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 905aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 906aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 907aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 908aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 909c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu // Redundant probably. But no harm in updating state again. 910e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(false, false); 911207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 912d970998b0d489774ad1c5b94b47d233912f00214San Mehat mConnector.doCommand(String.format( 913d970998b0d489774ad1c5b94b47d233912f00214San Mehat "volume unmount %s%s", path, (force ? " force" : ""))); 914e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu // We unmounted the volume. None of the asec containers are available now. 915e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu synchronized (mAsecMountSet) { 916e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mAsecMountSet.clear(); 917e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu } 918b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationSucceeded; 919207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 920207e538350665cea00e1aa70b8094beca4a34e45San Mehat // Don't worry about mismatch in PackageManager since the 921207e538350665cea00e1aa70b8094beca4a34e45San Mehat // call back will handle the status changes any way. 922207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 923207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedVolNotMounted) { 924a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageNotMounted; 925d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else if (code == VoldResponseCode.OpFailedStorageBusy) { 926d970998b0d489774ad1c5b94b47d233912f00214San Mehat return StorageResultCode.OperationFailedStorageBusy; 927207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 928b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedInternalError; 929207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 930207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 931207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 932207e538350665cea00e1aa70b8094beca4a34e45San Mehat 933207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doFormatVolume(String path) { 934207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 935207e538350665cea00e1aa70b8094beca4a34e45San Mehat String cmd = String.format("volume format %s", path); 936207e538350665cea00e1aa70b8094beca4a34e45San Mehat mConnector.doCommand(cmd); 937b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationSucceeded; 938207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 939207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 940207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedNoMedia) { 941b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedNoMedia; 942207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { 943b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedMediaCorrupt; 944207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 945b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedInternalError; 946207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 947207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 948207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 949207e538350665cea00e1aa70b8094beca4a34e45San Mehat 950b104340496e3a531e26c8f428c808eca0e039f50San Mehat private boolean doGetVolumeShared(String path, String method) { 951b104340496e3a531e26c8f428c808eca0e039f50San Mehat String cmd = String.format("volume shared %s %s", path, method); 952a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root ArrayList<String> rsp; 953a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root 954a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root try { 955a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root rsp = mConnector.doCommand(cmd); 956a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } catch (NativeDaemonConnectorException ex) { 957a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root Slog.e(TAG, "Failed to read response to volume shared " + path + " " + method); 958a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return false; 959a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } 960b104340496e3a531e26c8f428c808eca0e039f50San Mehat 961b104340496e3a531e26c8f428c808eca0e039f50San Mehat for (String line : rsp) { 962a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root String[] tok = line.split(" "); 963a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root if (tok.length < 3) { 964a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root Slog.e(TAG, "Malformed response to volume shared " + path + " " + method + " command"); 965a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return false; 966a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } 967a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root 968b104340496e3a531e26c8f428c808eca0e039f50San Mehat int code; 969b104340496e3a531e26c8f428c808eca0e039f50San Mehat try { 970b104340496e3a531e26c8f428c808eca0e039f50San Mehat code = Integer.parseInt(tok[0]); 971b104340496e3a531e26c8f428c808eca0e039f50San Mehat } catch (NumberFormatException nfe) { 972a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Error parsing code %s", tok[0])); 973b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 974b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 975b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (code == VoldResponseCode.ShareEnabledResult) { 976a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return "enabled".equals(tok[2]); 977b104340496e3a531e26c8f428c808eca0e039f50San Mehat } else { 978a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Unexpected response code %d", code)); 979b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 980b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 981b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 982a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Got an empty response"); 983b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 984b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 985b104340496e3a531e26c8f428c808eca0e039f50San Mehat 986207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void notifyShareAvailabilityChange(String method, final boolean avail) { 9877fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat if (!method.equals("ums")) { 988a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Ignoring unsupported share method {" + method + "}"); 9897fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat return; 9907fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 9911f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat 9924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 9934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for (int i = mListeners.size() -1; i >= 0; i--) { 9944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = mListeners.get(i); 9951f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat try { 996b104340496e3a531e26c8f428c808eca0e039f50San Mehat bl.mListener.onUsbMassStorageConnectionChanged(avail); 9974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 998a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener dead"); 9994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(i); 10001f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } catch (Exception ex) { 1001a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener failed", ex); 10021f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 10031f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 10044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 10057fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 1006207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (mBooted == true) { 10076a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat sendUmsIntent(avail); 10086a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } else { 10096a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat mSendUmsConnectedOnBoot = avail; 10101f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 10112fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat 10122fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat final String path = Environment.getExternalStorageDirectory().getPath(); 10132fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat if (avail == false && getVolumeState(path).equals(Environment.MEDIA_SHARED)) { 10142fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat /* 10152fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat * USB mass storage disconnected while enabled 10162fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat */ 10172fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat new Thread() { 10185af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 10192fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat public void run() { 10202fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat try { 10212fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat int rc; 1022a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Disabling UMS after cable disconnect"); 10232fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat doShareUnshareVolume(path, "ums", false); 10242fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { 1025a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format( 10262fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat "Failed to remount {%s} on UMS enabled-disconnect (%d)", 10272fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat path, rc)); 10282fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 10292fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } catch (Exception ex) { 1030a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Failed to mount media on UMS enabled-disconnect", ex); 10312fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 10322fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 10332fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat }.start(); 10342fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10376a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private void sendUmsIntent(boolean c) { 10386a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat mContext.sendBroadcast( 10396a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat new Intent((c ? Intent.ACTION_UMS_CONNECTED : Intent.ACTION_UMS_DISCONNECTED))); 10406a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } 10416a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat 1042207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void validatePermission(String perm) { 10434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) { 10444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new SecurityException(String.format("Requires %s permission", perm)); 10454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 10467fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 10477fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1049207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Constructs a new MountService instance 1050207e538350665cea00e1aa70b8094beca4a34e45San Mehat * 1051207e538350665cea00e1aa70b8094beca4a34e45San Mehat * @param context Binder context for this service 1052207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 1053207e538350665cea00e1aa70b8094beca4a34e45San Mehat public MountService(Context context) { 1054207e538350665cea00e1aa70b8094beca4a34e45San Mehat mContext = context; 1055207e538350665cea00e1aa70b8094beca4a34e45San Mehat 1056f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood mExternalStoragePath = Environment.getExternalStorageDirectory().getPath(); 105703559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood mEmulateExternalStorage = context.getResources().getBoolean( 105803559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood com.android.internal.R.bool.config_emulateExternalStorage); 105903559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood if (mEmulateExternalStorage) { 106003559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood Slog.d(TAG, "using emulated external storage"); 1061f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood mVolumeStates.put(mExternalStoragePath, Environment.MEDIA_MOUNTED); 106203559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood } 106303559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood 1064207e538350665cea00e1aa70b8094beca4a34e45San Mehat // XXX: This will go away soon in favor of IMountServiceObserver 1065207e538350665cea00e1aa70b8094beca4a34e45San Mehat mPms = (PackageManagerService) ServiceManager.getService("package"); 1066207e538350665cea00e1aa70b8094beca4a34e45San Mehat 1067207e538350665cea00e1aa70b8094beca4a34e45San Mehat mContext.registerReceiver(mBroadcastReceiver, 1068207e538350665cea00e1aa70b8094beca4a34e45San Mehat new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); 1069207e538350665cea00e1aa70b8094beca4a34e45San Mehat 10705f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandlerThread = new HandlerThread("MountService"); 10715f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandlerThread.start(); 10725f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandler = new MountServiceHandler(mHandlerThread.getLooper()); 10735f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler 1074a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Add OBB Action Handler to MountService thread. 1075a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper()); 1076a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1077c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen /* 1078c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * Vold does not run in the simulator, so pretend the connector thread 1079c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * ran and did its thing. 1080c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen */ 1081c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen if ("simulator".equals(SystemProperties.get("ro.product.device"))) { 1082c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen mReady = true; 1083c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen mUmsEnabling = true; 1084c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen return; 1085c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen } 1086c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen 1087305bcbf0c961840c4505770d084a1caacc074dbbKenny Root /* 1088305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * Create the connection to vold with a maximum queue of twice the 1089305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * amount of containers we'd ever expect to have. This keeps an 1090305bcbf0c961840c4505770d084a1caacc074dbbKenny Root * "asec list" from blocking a thread repeatedly. 1091305bcbf0c961840c4505770d084a1caacc074dbbKenny Root */ 1092305bcbf0c961840c4505770d084a1caacc074dbbKenny Root mConnector = new NativeDaemonConnector(this, "vold", 1093305bcbf0c961840c4505770d084a1caacc074dbbKenny Root PackageManagerService.MAX_CONTAINERS * 2, VOLD_TAG); 1094207e538350665cea00e1aa70b8094beca4a34e45San Mehat mReady = false; 1095305bcbf0c961840c4505770d084a1caacc074dbbKenny Root Thread thread = new Thread(mConnector, VOLD_TAG); 1096207e538350665cea00e1aa70b8094beca4a34e45San Mehat thread.start(); 1097207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1098207e538350665cea00e1aa70b8094beca4a34e45San Mehat 1099207e538350665cea00e1aa70b8094beca4a34e45San Mehat /** 11004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Exposed API calls below here 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 11027fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 11034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void registerListener(IMountServiceListener listener) { 11044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 11054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = new MountServiceBinderListener(listener); 11064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 11074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat listener.asBinder().linkToDeath(bl, 0); 11084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.add(bl); 11094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 1110a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to link to listener death"); 11114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 11127fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void unregisterListener(IMountServiceListener listener) { 11164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 11174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for(MountServiceBinderListener bl : mListeners) { 11184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (bl.mListener == listener) { 11194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(mListeners.indexOf(bl)); 11204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return; 11214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 11224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11266ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu public void shutdown(final IMountShutdownObserver observer) { 11274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.SHUTDOWN); 11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1129a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Shutting down"); 1130f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood synchronized (mVolumeStates) { 1131f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood for (String path : mVolumeStates.keySet()) { 1132f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood String state = mVolumeStates.get(path); 1133f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood 1134f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood if (state.equals(Environment.MEDIA_SHARED)) { 1135f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood /* 1136f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood * If the media is currently shared, unshare it. 1137f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood * XXX: This is still dangerous!. We should not 1138f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood * be rebooting at *all* if UMS is enabled, since 1139f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood * the UMS host could have dirty FAT cache entries 1140f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood * yet to flush. 1141f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood */ 1142f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood setUsbMassStorageEnabled(false); 1143f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood } else if (state.equals(Environment.MEDIA_CHECKING)) { 1144f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood /* 1145f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood * If the media is being checked, then we need to wait for 1146f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood * it to complete before being able to proceed. 1147f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood */ 1148f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood // XXX: @hackbod - Should we disable the ANR timer here? 1149f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood int retries = 30; 1150f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) { 1151f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood try { 1152f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood Thread.sleep(1000); 1153f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood } catch (InterruptedException iex) { 1154f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood Slog.e(TAG, "Interrupted while waiting for media", iex); 1155f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood break; 1156f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood } 1157f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood state = Environment.getExternalStorageState(); 1158f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood } 1159f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood if (retries == 0) { 1160f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood Slog.e(TAG, "Timed out waiting for media to check"); 1161f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood } 11624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 11637fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 1164f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood if (state.equals(Environment.MEDIA_MOUNTED)) { 1165f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood // Post a unmount message. 1166f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood ShutdownCallBack ucb = new ShutdownCallBack(path, observer); 1167f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb)); 1168f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood } else if (observer != null) { 1169f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood /* 1170f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood * Observer is waiting for onShutDownComplete when we are done. 1171f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood * Since nothing will be done send notification directly so shutdown 1172f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood * sequence can continue. 1173f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood */ 1174f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood try { 1175f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood observer.onShutDownComplete(StorageResultCode.OperationSucceeded); 1176f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood } catch (RemoteException e) { 1177f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood Slog.w(TAG, "RemoteException when shutting down"); 1178f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood } 1179f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood } 11805d0db4d356346bee68aec9a124df70dbaa9aaed1Johan Alfven } 11811f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11840eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private boolean getUmsEnabling() { 11850eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu synchronized (mListeners) { 11860eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu return mUmsEnabling; 11870eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 11880eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 11890eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 11900eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private void setUmsEnabling(boolean enable) { 11910eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu synchronized (mListeners) { 1192fc71125104650c61ab5b04f4c943de761d58cba6Tony Wu mUmsEnabling = enable; 11930eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 11940eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 11950eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 1196b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageConnected() { 1197207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 11987fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 11990eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (getUmsEnabling()) { 1200b104340496e3a531e26c8f428c808eca0e039f50San Mehat return true; 1201b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1202b104340496e3a531e26c8f428c808eca0e039f50San Mehat return doGetShareMethodAvailable("ums"); 12034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12050eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu public void setUsbMassStorageEnabled(boolean enable) { 1206207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 12070eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 12080eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 12090eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // TODO: Add support for multiple share methods 1210b104340496e3a531e26c8f428c808eca0e039f50San Mehat 12110eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 12120eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * If the volume is mounted and we're enabling then unmount it 12130eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 12140eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String path = Environment.getExternalStorageDirectory().getPath(); 12150eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String vs = getVolumeState(path); 12160eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String method = "ums"; 12170eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (enable && vs.equals(Environment.MEDIA_MOUNTED)) { 12180eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Override for isUsbMassStorageEnabled() 12190eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu setUmsEnabling(enable); 12200eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true); 12210eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb)); 12220eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Clear override 12230eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu setUmsEnabling(false); 12240eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 12250eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 12260eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * If we disabled UMS then mount the volume 12270eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 12280eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (!enable) { 12290eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doShareUnshareVolume(path, method, enable); 12300eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (doMountVolume(path) != StorageResultCode.OperationSucceeded) { 1231a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to remount " + path + 12320eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu " after disabling share method " + method); 12330eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 12340eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * Even though the mount failed, the unshare didn't so don't indicate an error. 12350eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * The mountVolume() call will have set the storage state and sent the necessary 12360eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * broadcasts. 12370eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 12380eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 12390eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 12404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1242b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageEnabled() { 1243207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1244b104340496e3a531e26c8f428c808eca0e039f50San Mehat return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums"); 12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12469ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * @return state of the volume at the specified mount point 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String getVolumeState(String mountPoint) { 1251f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood synchronized (mVolumeStates) { 1252f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood String state = mVolumeStates.get(mountPoint); 1253f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood if (state == null) { 1254f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume"); 1255f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood throw new IllegalArgumentException(); 1256f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood } 12574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1258f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood return state; 1259f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood } 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1262e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root public boolean isExternalStorageEmulated() { 1263e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root return mEmulateExternalStorage; 1264e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root } 1265e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root 12664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int mountVolume(String path) { 12674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1269207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1270207e538350665cea00e1aa70b8094beca4a34e45San Mehat return doMountVolume(path); 12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1273c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu public void unmountVolume(String path, boolean force) { 12744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1275207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12778a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu String volState = getVolumeState(path); 1278a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path + " force = " + force); 12798a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (Environment.MEDIA_UNMOUNTED.equals(volState) || 12808a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_REMOVED.equals(volState) || 12818a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_SHARED.equals(volState) || 12828a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_UNMOUNTABLE.equals(volState)) { 12838a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // Media already unmounted or cannot be unmounted. 12848a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // TODO return valid return code when adding observer call back. 12858a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu return; 12868a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 1287c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = new UnmountCallBack(path, force); 1288c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb)); 12894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int formatVolume(String path) { 12924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); 1293207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1295207e538350665cea00e1aa70b8094beca4a34e45San Mehat return doFormatVolume(path); 12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12973697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1298c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat public int []getStorageUsers(String path) { 1299c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1300c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat waitForReady(); 1301c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat try { 1302c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat String[] r = mConnector.doListCommand( 1303c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat String.format("storage users %s", path), 1304c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat VoldResponseCode.StorageUsersListResult); 1305c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat // FMT: <pid> <process name> 1306c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat int[] data = new int[r.length]; 1307c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat for (int i = 0; i < r.length; i++) { 1308c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat String []tok = r[i].split(" "); 1309c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat try { 1310c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat data[i] = Integer.parseInt(tok[0]); 1311c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } catch (NumberFormatException nfe) { 1312a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Error parsing pid %s", tok[0])); 1313c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return new int[0]; 1314c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1315c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1316c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return data; 1317c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } catch (NativeDaemonConnectorException e) { 1318a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to retrieve storage users list", e); 1319c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return new int[0]; 1320c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1321c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1322c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat 1323b104340496e3a531e26c8f428c808eca0e039f50San Mehat private void warnOnNotMounted() { 1324b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 1325a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "getSecureContainerList() called when storage not mounted"); 1326b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1327b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1328b104340496e3a531e26c8f428c808eca0e039f50San Mehat 13294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String[] getSecureContainerList() { 13304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 1331207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1332b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1333f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 13344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 13354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult); 13364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 13374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return new String[0]; 133802735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 13393697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 13403697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 13414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int createSecureContainer(String id, int sizeMb, String fstype, 13424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String key, int ownerUid) { 13434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_CREATE); 1344207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1345b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 13464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1347b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 13484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String cmd = String.format("asec create %s %d %s %s %d", id, sizeMb, fstype, key, ownerUid); 13494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 13504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 13514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1352b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 135302735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1354a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1355a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (rc == StorageResultCode.OperationSucceeded) { 1356a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1357a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat mAsecMountSet.add(id); 1358a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1359a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 13604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 13613697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 13623697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 13634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int finalizeSecureContainer(String id) { 13644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_CREATE); 1365b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 13664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1367b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 13684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 13694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(String.format("asec finalize %s", id)); 1370a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat /* 1371a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat * Finalization does a remount, so no need 1372a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat * to update mAsecMountSet 1373a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat */ 13744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1375b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 137602735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 13774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 13783697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 13793697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1380d970998b0d489774ad1c5b94b47d233912f00214San Mehat public int destroySecureContainer(String id, boolean force) { 13814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_DESTROY); 1382207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1383b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1384f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 1385aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 1386aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 1387aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 1388aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 1389aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 1390aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 1391aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 1392aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 1393b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 13944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1395d970998b0d489774ad1c5b94b47d233912f00214San Mehat mConnector.doCommand(String.format("asec destroy %s%s", id, (force ? " force" : ""))); 13964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1397d970998b0d489774ad1c5b94b47d233912f00214San Mehat int code = e.getCode(); 1398d970998b0d489774ad1c5b94b47d233912f00214San Mehat if (code == VoldResponseCode.OpFailedStorageBusy) { 1399d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedStorageBusy; 1400d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else { 1401d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedInternalError; 1402d970998b0d489774ad1c5b94b47d233912f00214San Mehat } 140302735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1404a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1405a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (rc == StorageResultCode.OperationSucceeded) { 1406a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1407a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (mAsecMountSet.contains(id)) { 1408a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat mAsecMountSet.remove(id); 1409a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1410a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1411a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1412a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 14134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 14143697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 14159ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 14164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int mountSecureContainer(String id, String key, int ownerUid) { 14174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 1418207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1419b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 14204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1421a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1422a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (mAsecMountSet.contains(id)) { 1423a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageMounted; 1424a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1425a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1426a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1427b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 14284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String cmd = String.format("asec mount %s %s %d", id, key, ownerUid); 14294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 14304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 14314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1432f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root int code = e.getCode(); 1433f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root if (code != VoldResponseCode.OpFailedStorageBusy) { 1434f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root rc = StorageResultCode.OperationFailedInternalError; 1435f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root } 143602735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 14376cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 14386cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (rc == StorageResultCode.OperationSucceeded) { 14396cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 14406cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat mAsecMountSet.add(id); 14416cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 14426cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 14434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 14443697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 14453697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1446d970998b0d489774ad1c5b94b47d233912f00214San Mehat public int unmountSecureContainer(String id, boolean force) { 14474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 1448207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1449b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 14504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 14516cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 14526cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (!mAsecMountSet.contains(id)) { 1453a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageNotMounted; 14546cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 14556cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 14566cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 1457aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root /* 1458aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * Force a GC to make sure AssetManagers in other threads of the 1459aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * system_server are cleaned up. We have to do this since AssetManager 1460aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * instances are kept as a WeakReference and it's possible we have files 1461aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root * open on the external storage. 1462aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root */ 1463aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root Runtime.getRuntime().gc(); 1464aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root 1465b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 1466d970998b0d489774ad1c5b94b47d233912f00214San Mehat String cmd = String.format("asec unmount %s%s", id, (force ? " force" : "")); 14674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 14684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 14694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1470d970998b0d489774ad1c5b94b47d233912f00214San Mehat int code = e.getCode(); 1471d970998b0d489774ad1c5b94b47d233912f00214San Mehat if (code == VoldResponseCode.OpFailedStorageBusy) { 1472d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedStorageBusy; 1473d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else { 1474d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedInternalError; 1475d970998b0d489774ad1c5b94b47d233912f00214San Mehat } 147602735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 14776cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 14786cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (rc == StorageResultCode.OperationSucceeded) { 14796cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 14806cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat mAsecMountSet.remove(id); 14816cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 14826cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 14834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 14849dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat } 14859dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat 14866cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat public boolean isSecureContainerMounted(String id) { 14876cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 14886cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat waitForReady(); 14896cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat warnOnNotMounted(); 14906cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 14916cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 14926cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat return mAsecMountSet.contains(id); 14936cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 14946cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 14956cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 14964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int renameSecureContainer(String oldId, String newId) { 14974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_RENAME); 1498207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1499b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 15004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1501a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 150285451ee15fdf6cae371dc3005441988c7d426401San Mehat /* 15039ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks * Because a mounted container has active internal state which cannot be 150485451ee15fdf6cae371dc3005441988c7d426401San Mehat * changed while active, we must ensure both ids are not currently mounted. 150585451ee15fdf6cae371dc3005441988c7d426401San Mehat */ 150685451ee15fdf6cae371dc3005441988c7d426401San Mehat if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) { 1507a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageMounted; 1508a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1509a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1510a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1511b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 15124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String cmd = String.format("asec rename %s %s", oldId, newId); 15134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 15144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 15154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1516b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 151702735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1518a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 15194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 152045f61040823d8c442838f75cde8760f236603daeSan Mehat } 152145f61040823d8c442838f75cde8760f236603daeSan Mehat 15224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String getSecureContainerPath(String id) { 15234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 1524207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1525b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1526f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 15272d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat try { 15282d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat ArrayList<String> rsp = mConnector.doCommand(String.format("asec path %s", id)); 15292d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat String []tok = rsp.get(0).split(" "); 153022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat int code = Integer.parseInt(tok[0]); 15312d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat if (code != VoldResponseCode.AsecPathResult) { 15322d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat throw new IllegalStateException(String.format("Unexpected response code %d", code)); 15332d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat } 15342d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat return tok[1]; 15352d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat } catch (NativeDaemonConnectorException e) { 15362d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat int code = e.getCode(); 15372d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat if (code == VoldResponseCode.OpFailedStorageNotFound) { 15382d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat throw new IllegalArgumentException(String.format("Container '%s' not found", id)); 153922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else { 15402d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat throw new IllegalStateException(String.format("Unexpected response code %d", code)); 154122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 154222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 154322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 1544e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu 1545e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu public void finishMediaUpdate() { 1546e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE); 1547e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu } 154802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1549a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) { 1550a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (callerUid == android.os.Process.SYSTEM_UID) { 1551a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return true; 1552a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1553a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 155402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (packageName == null) { 155502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return false; 155602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 155702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 155802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root final int packageUid = mPms.getPackageUid(packageName); 155902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 156002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (DEBUG_OBB) { 156102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root Slog.d(TAG, "packageName = " + packageName + ", packageUid = " + 156202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root packageUid + ", callerUid = " + callerUid); 156302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 156402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 156502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return callerUid == packageUid; 156602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 156702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 156802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root public String getMountedObbPath(String filename) { 1569af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (filename == null) { 1570af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalArgumentException("filename cannot be null"); 1571af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1572af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 157302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root waitForReady(); 157402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root warnOnNotMounted(); 157502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 157602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root try { 157702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root ArrayList<String> rsp = mConnector.doCommand(String.format("obb path %s", filename)); 157802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root String []tok = rsp.get(0).split(" "); 157902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root int code = Integer.parseInt(tok[0]); 158002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (code != VoldResponseCode.AsecPathResult) { 158102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root throw new IllegalStateException(String.format("Unexpected response code %d", code)); 158202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 158302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root return tok[1]; 158402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } catch (NativeDaemonConnectorException e) { 158502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root int code = e.getCode(); 158602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root if (code == VoldResponseCode.OpFailedStorageNotFound) { 1587a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return null; 158802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } else { 158902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root throw new IllegalStateException(String.format("Unexpected response code %d", code)); 159002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 159102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 159202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 159302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 159402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root public boolean isObbMounted(String filename) { 1595af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (filename == null) { 1596af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalArgumentException("filename cannot be null"); 1597af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1598af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1599a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root synchronized (mObbMounts) { 1600af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return mObbPathToStateMap.containsKey(filename); 1601a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1602a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1603a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1604af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root public void mountObb(String filename, String key, IObbActionListener token, int nonce) 1605735de3b38abbd6564082a819377673ee593744a6Kenny Root throws RemoteException { 1606f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root if (filename == null) { 1607f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root throw new IllegalArgumentException("filename cannot be null"); 1608f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root } 1609f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root 1610af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (token == null) { 1611af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalArgumentException("token cannot be null"); 16122942391801b79816c5eb77d7ac94c4a65f26af48Kenny Root } 1613735de3b38abbd6564082a819377673ee593744a6Kenny Root 1614af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final int callerUid = Binder.getCallingUid(); 1615af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbState obbState = new ObbState(filename, callerUid, token, nonce); 1616af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbAction action = new MountObbAction(obbState, key); 1617a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 1618a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1619a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1620a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Send to OBB handler: " + action.toString()); 162102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 162202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1623af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root public void unmountObb(String filename, boolean force, IObbActionListener token, int nonce) 1624af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throws RemoteException { 1625f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root if (filename == null) { 1626f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root throw new IllegalArgumentException("filename cannot be null"); 1627f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root } 1628f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root 1629af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final int callerUid = Binder.getCallingUid(); 1630af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbState obbState = new ObbState(filename, callerUid, token, nonce); 1631af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbAction action = new UnmountObbAction(obbState, force); 1632a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); 1633a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1634a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1635a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Send to OBB handler: " + action.toString()); 1636a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 163702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 16385af0b916f850486cff4797355bf9e7dc3352fe00Jason parks public int decryptStorage(String password) { 1639f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (TextUtils.isEmpty(password)) { 1640f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks throw new IllegalArgumentException("password cannot be empty"); 16415af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 16425af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 16438888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 16448888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks "no permission to access the crypt keeper"); 16455af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 16465af0b916f850486cff4797355bf9e7dc3352fe00Jason parks waitForReady(); 16475af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 16485af0b916f850486cff4797355bf9e7dc3352fe00Jason parks if (DEBUG_EVENTS) { 16495af0b916f850486cff4797355bf9e7dc3352fe00Jason parks Slog.i(TAG, "decrypting storage..."); 16505af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 16515af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 16525af0b916f850486cff4797355bf9e7dc3352fe00Jason parks try { 16539ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks ArrayList<String> rsp = mConnector.doCommand("cryptfs checkpw " + password); 1654f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks String[] tokens = rsp.get(0).split(" "); 16559ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 1656f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (tokens == null || tokens.length != 2) { 16579ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks return -1; 16589ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks } 16599ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 1660f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks int code = Integer.parseInt(tokens[1]); 16619ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 16629ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks if (code == 0) { 16639ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks // Decrypt was successful. Post a delayed message before restarting in order 16649ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks // to let the UI to clear itself 16659ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks mHandler.postDelayed(new Runnable() { 16669ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks public void run() { 16679ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks mConnector.doCommand(String.format("cryptfs restart")); 16689ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks } 1669f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks }, 1000); // 1 second 16709ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks } 16719ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks 16729ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks return code; 16735af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } catch (NativeDaemonConnectorException e) { 16745af0b916f850486cff4797355bf9e7dc3352fe00Jason parks // Decryption failed 16755af0b916f850486cff4797355bf9e7dc3352fe00Jason parks return e.getCode(); 16765af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 16775af0b916f850486cff4797355bf9e7dc3352fe00Jason parks } 16785af0b916f850486cff4797355bf9e7dc3352fe00Jason parks 167956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks public int encryptStorage(String password) { 1680f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (TextUtils.isEmpty(password)) { 1681f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks throw new IllegalArgumentException("password cannot be empty"); 168256aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 168356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 16848888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 16858888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks "no permission to access the crypt keeper"); 168656aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 168756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks waitForReady(); 168856aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 168956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks if (DEBUG_EVENTS) { 16908888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks Slog.i(TAG, "encrypting storage..."); 169156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 169256aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 169356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks try { 16949ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks mConnector.doCommand(String.format("cryptfs enablecrypto inplace %s", password)); 169556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } catch (NativeDaemonConnectorException e) { 169656aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks // Encryption failed 169756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks return e.getCode(); 169856aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 169956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 170056aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks return 0; 170156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks } 170256aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks 1703f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks public int changeEncryptionPassword(String password) { 1704f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (TextUtils.isEmpty(password)) { 1705f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks throw new IllegalArgumentException("password cannot be empty"); 1706f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 1707f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1708f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER, 1709f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks "no permission to access the crypt keeper"); 1710f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1711f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks waitForReady(); 1712f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1713f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (DEBUG_EVENTS) { 1714f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks Slog.i(TAG, "changing encryption password..."); 1715f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 1716f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1717f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks try { 1718f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks ArrayList<String> response = mConnector.doCommand("cryptfs changepw " + password); 1719f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1720f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks String[] tokens = response.get(0).split(" "); 1721f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1722f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks if (tokens == null || tokens.length != 2) { 1723f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks return -1; 1724f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 1725f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1726f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks return Integer.parseInt(tokens[1]); 1727f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } catch (NativeDaemonConnectorException e) { 1728f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks // Encryption failed 1729f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks return e.getCode(); 1730f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 1731f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks } 1732f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks 1733af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private void addObbStateLocked(ObbState obbState) throws RemoteException { 1734af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IBinder binder = obbState.getBinder(); 1735af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root List<ObbState> obbStates = mObbMounts.get(binder); 17365919ac6b4188285324646772501ef4b97b353cf4Kenny Root 1737af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates == null) { 1738af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates = new ArrayList<ObbState>(); 1739af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.put(binder, obbStates); 1740af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 1741af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root for (final ObbState o : obbStates) { 1742af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (o.filename.equals(obbState.filename)) { 1743af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw new IllegalStateException("Attempt to add ObbState twice. " 1744af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + "This indicates an error in the MountService logic."); 17455919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 17465919ac6b4188285324646772501ef4b97b353cf4Kenny Root } 174702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 174802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1749af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates.add(obbState); 1750af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 1751af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState.link(); 1752af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (RemoteException e) { 1753af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root /* 1754af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * The binder died before we could link it, so clean up our state 1755af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * and return failure. 1756af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root */ 1757af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStates.remove(obbState); 1758af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.isEmpty()) { 1759af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.remove(binder); 176005105f7abe02b2dff91d6260b3628c8b97816babKenny Root } 17615919ac6b4188285324646772501ef4b97b353cf4Kenny Root 1762af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // Rethrow the error so mountObb can get it 1763af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root throw e; 176402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 1765af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1766af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbPathToStateMap.put(obbState.filename, obbState); 1767a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 176802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1769af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root private void removeObbStateLocked(ObbState obbState) { 1770af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final IBinder binder = obbState.getBinder(); 1771af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStates = mObbMounts.get(binder); 1772af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates != null) { 1773af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.remove(obbState)) { 1774af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState.unlink(); 1775af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1776af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbStates.isEmpty()) { 1777af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbMounts.remove(binder); 1778af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 177938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 1780af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1781af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbPathToStateMap.remove(obbState.filename); 178238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 178338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 1784a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private class ObbActionHandler extends Handler { 1785a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean mBound = false; 1786480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root private final List<ObbAction> mActions = new LinkedList<ObbAction>(); 1787a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1788a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbActionHandler(Looper l) { 1789a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(l); 1790a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1791a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1792a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 1793a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleMessage(Message msg) { 1794a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root switch (msg.what) { 1795a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_RUN_ACTION: { 1796480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root final ObbAction action = (ObbAction) msg.obj; 1797a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1798a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1799a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString()); 1800a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1801a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // If a bind was already initiated we don't really 1802a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // need to do anything. The pending install 1803a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // will be processed later on. 1804a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!mBound) { 1805a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // If this is the only one pending we might 1806a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // have to bind to the service again. 1807a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!connectToService()) { 1808a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Failed to bind to media container service"); 1809a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 1810a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return; 1811a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1812a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1813735de3b38abbd6564082a819377673ee593744a6Kenny Root 1814735de3b38abbd6564082a819377673ee593744a6Kenny Root mActions.add(action); 1815a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 1816a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1817a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_BOUND: { 1818a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1819a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_BOUND"); 1820a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (msg.obj != null) { 1821a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContainerService = (IMediaContainerService) msg.obj; 1822a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1823a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mContainerService == null) { 1824a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Something seriously wrong. Bail out 1825a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Cannot bind to media container service"); 1826a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root for (ObbAction action : mActions) { 1827a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Indicate service bind error 1828a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 1829a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1830a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.clear(); 1831a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else if (mActions.size() > 0) { 1832480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root final ObbAction action = mActions.get(0); 1833a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (action != null) { 1834a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.execute(this); 1835a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1836a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 1837a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Should never happen ideally. 1838a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.w(TAG, "Empty queue"); 1839a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1840a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 1841a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1842a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_RECONNECT: { 1843a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1844a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_RECONNECT"); 1845a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() > 0) { 1846a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mBound) { 1847a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root disconnectService(); 1848a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1849a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (!connectToService()) { 1850a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.e(TAG, "Failed to bind to media container service"); 1851a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root for (ObbAction action : mActions) { 1852a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Indicate service bind error 1853a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root action.handleError(); 1854a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1855a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.clear(); 1856a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1857a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1858a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 1859a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1860a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root case OBB_MCS_UNBIND: { 1861a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1862a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "OBB_MCS_UNBIND"); 1863a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1864a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Delete pending install 1865a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() > 0) { 1866a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mActions.remove(0); 1867a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1868a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mActions.size() == 0) { 1869a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mBound) { 1870a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root disconnectService(); 1871a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1872a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 1873a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // There are more pending requests in queue. 1874a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // Just post MCS_BOUND message to trigger processing 1875a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root // of next pending install. 1876a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND); 1877a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1878a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root break; 1879a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1880af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root case OBB_FLUSH_MOUNT_STATE: { 1881af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final String path = (String) msg.obj; 1882af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1883af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 1884af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.i(TAG, "Flushing all OBB state for path " + path); 1885af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1886af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 1887af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>(); 1888af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1889af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Iterator<Entry<String, ObbState>> i = 1890af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbPathToStateMap.entrySet().iterator(); 1891af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (i.hasNext()) { 1892af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Entry<String, ObbState> obbEntry = i.next(); 1893af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1894af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root /* 1895af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * If this entry's source file is in the volume path 1896af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * that got unmounted, remove it because it's no 1897af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * longer valid. 1898af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root */ 1899af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbEntry.getKey().startsWith(path)) { 1900af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbStatesToRemove.add(obbEntry.getValue()); 1901af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1902af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1903af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1904af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root for (final ObbState obbState : obbStatesToRemove) { 1905af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 1906af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.i(TAG, "Removing state for " + obbState.filename); 1907af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1908af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root removeObbStateLocked(obbState); 1909af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 1910af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 1911af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState.token.onObbResult(obbState.filename, obbState.nonce, 1912af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root OnObbStateChangeListener.UNMOUNTED); 1913af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (RemoteException e) { 1914af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.i(TAG, "Couldn't send unmount notification for OBB: " 1915af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + obbState.filename); 1916af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1917af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1918af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 1919af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root break; 1920af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 192102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 192202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 192302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1924a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean connectToService() { 1925a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1926a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Trying to bind to DefaultContainerService"); 1927a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1928a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); 1929a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) { 1930a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mBound = true; 1931a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return true; 193202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 1933a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return false; 1934a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1935a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1936a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private void disconnectService() { 1937a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContainerService = null; 1938a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mBound = false; 1939a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mContext.unbindService(mDefContainerConn); 194002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 194102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 194202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1943a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root abstract class ObbAction { 1944a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private static final int MAX_RETRIES = 3; 1945a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private int mRetries; 194602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1947a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbState mObbState; 1948a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 1949a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root ObbAction(ObbState obbState) { 1950a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbState = obbState; 195102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 195202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 1953a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void execute(ObbActionHandler handler) { 1954a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root try { 1955a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1956a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Starting to execute action: " + this.toString()); 1957a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mRetries++; 1958a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (mRetries > MAX_RETRIES) { 1959a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); 1960480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 1961a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleError(); 1962a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return; 1963a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } else { 1964a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleExecute(); 1965a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1966a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Posting install MCS_UNBIND"); 1967a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 1968a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 1969a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } catch (RemoteException e) { 1970a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1971a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.i(TAG, "Posting install MCS_RECONNECT"); 1972a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT); 1973a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } catch (Exception e) { 1974a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root if (DEBUG_OBB) 1975a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root Slog.d(TAG, "Error handling OBB action", e); 1976a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root handleError(); 197717eb6fb07cc6965f09c51adc70b3c291f57a784aKenny Root mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND); 197802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 1979a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 198002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 198105105f7abe02b2dff91d6260b3628c8b97816babKenny Root abstract void handleExecute() throws RemoteException, IOException; 1982a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root abstract void handleError(); 198338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 198438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root protected ObbInfo getObbInfo() throws IOException { 198538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root ObbInfo obbInfo; 198638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root try { 198738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root obbInfo = mContainerService.getObbInfo(mObbState.filename); 198838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } catch (RemoteException e) { 198938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for " 199038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root + mObbState.filename); 199138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root obbInfo = null; 199238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 199338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root if (obbInfo == null) { 199438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root throw new IOException("Couldn't read OBB file: " + mObbState.filename); 199538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 199638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return obbInfo; 199738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 199838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 1999af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root protected void sendNewStatusOrIgnore(int status) { 2000af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (mObbState == null || mObbState.token == null) { 2001af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2002af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2003af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 200438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root try { 2005af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbState.token.onObbResult(mObbState.filename, mObbState.nonce, status); 200638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } catch (RemoteException e) { 200738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged"); 200838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 200938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2010a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2011a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2012a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class MountObbAction extends ObbAction { 2013a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private String mKey; 2014a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2015a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root MountObbAction(ObbState obbState, String key) { 2016a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(obbState); 2017a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mKey = key; 2018a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2019a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 20205af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 2021735de3b38abbd6564082a819377673ee593744a6Kenny Root public void handleExecute() throws IOException, RemoteException { 2022af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root waitForReady(); 2023af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root warnOnNotMounted(); 2024af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 202538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root final ObbInfo obbInfo = getObbInfo(); 202638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2027af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mObbState.callerUid)) { 2028af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename 2029af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + " which is owned by " + obbInfo.packageName); 2030af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); 2031af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2032af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2033af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2034af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final boolean isMounted; 2035af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 2036af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root isMounted = mObbPathToStateMap.containsKey(obbInfo.filename); 2037af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2038af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (isMounted) { 2039af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename); 2040af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED); 2041af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2042af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2043af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 204438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root /* 2045af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * The filename passed in might not be the canonical name, so just 2046af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root * set the filename to the canonicalized version. 204738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root */ 2048af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbState.filename = obbInfo.filename; 204938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2050af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final String hashedKey; 2051af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (mKey == null) { 2052af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root hashedKey = "none"; 2053af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 2054af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 20553b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); 20563b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root 20573b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt, 20583b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE); 20593b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root SecretKey key = factory.generateSecret(ks); 20603b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root BigInteger bi = new BigInteger(key.getEncoded()); 20613b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root hashedKey = bi.toString(16); 2062af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NoSuchAlgorithmException e) { 20633b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root Slog.e(TAG, "Could not load PBKDF2 algorithm", e); 20643b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 20653b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root return; 20663b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root } catch (InvalidKeySpecException e) { 20673b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e); 20683b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 2069af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 207038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2071a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2072a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2073af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int rc = StorageResultCode.OperationSucceeded; 2074af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root String cmd = String.format("obb mount %s %s %d", mObbState.filename, hashedKey, 2075af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbState.callerUid); 2076af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 2077af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mConnector.doCommand(cmd); 2078af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NativeDaemonConnectorException e) { 2079af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int code = e.getCode(); 2080af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (code != VoldResponseCode.OpFailedStorageBusy) { 2081af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedInternalError; 2082a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2083af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2084a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2085af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (rc == StorageResultCode.OperationSucceeded) { 2086af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (DEBUG_OBB) 2087af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.d(TAG, "Successfully mounted OBB " + mObbState.filename); 208838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2089af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 2090af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root addObbStateLocked(mObbState); 2091a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 209238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2093af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED); 209402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } else { 209505105f7abe02b2dff91d6260b3628c8b97816babKenny Root Slog.e(TAG, "Couldn't mount OBB file: " + rc); 2096a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2097af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT); 209802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 209902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 210002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root 21015af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 2102a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleError() { 2103af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 210402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 2105a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2106a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 2107a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public String toString() { 2108a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root StringBuilder sb = new StringBuilder(); 2109a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("MountObbAction{"); 2110a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("filename="); 2111a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.filename); 2112a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",callerUid="); 2113a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.callerUid); 2114a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",token="); 2115a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.token != null ? mObbState.token.toString() : "NULL"); 2116af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sb.append(",binder="); 2117af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sb.append(mObbState.token != null ? mObbState.getBinder().toString() : "null"); 2118a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append('}'); 2119a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return sb.toString(); 2120a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2121a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2122a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2123a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root class UnmountObbAction extends ObbAction { 2124a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root private boolean mForceUnmount; 2125a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2126a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root UnmountObbAction(ObbState obbState, boolean force) { 2127a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root super(obbState); 2128a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root mForceUnmount = force; 2129a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2130a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 21315af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 213238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root public void handleExecute() throws IOException { 2133af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root waitForReady(); 2134af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root warnOnNotMounted(); 2135af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 213638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root final ObbInfo obbInfo = getObbInfo(); 2137a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2138af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final ObbState obbState; 213938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root synchronized (mObbMounts) { 2140af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root obbState = mObbPathToStateMap.get(obbInfo.filename); 2141af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 214238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2143af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbState == null) { 2144af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED); 2145af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2146a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2147a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2148af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (obbState.callerUid != mObbState.callerUid) { 2149af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Permission denied attempting to unmount OBB " + obbInfo.filename 2150af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root + " (owned by " + obbInfo.packageName + ")"); 2151af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); 2152af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root return; 2153af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 2154a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2155af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mObbState.filename = obbInfo.filename; 215638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2157af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int rc = StorageResultCode.OperationSucceeded; 2158af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root String cmd = String.format("obb unmount %s%s", mObbState.filename, 2159af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root (mForceUnmount ? " force" : "")); 2160af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root try { 2161af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root mConnector.doCommand(cmd); 2162af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } catch (NativeDaemonConnectorException e) { 2163af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root int code = e.getCode(); 2164af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (code == VoldResponseCode.OpFailedStorageBusy) { 2165af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedStorageBusy; 2166af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else if (code == VoldResponseCode.OpFailedStorageNotFound) { 2167af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root // If it's not mounted then we've already won. 2168af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationSucceeded; 2169af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } else { 2170af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root rc = StorageResultCode.OperationFailedInternalError; 2171a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2172a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 217338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2174af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root if (rc == StorageResultCode.OperationSucceeded) { 2175af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root synchronized (mObbMounts) { 2176af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root removeObbStateLocked(obbState); 2177af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 217838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2179af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED); 218038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } else { 2181af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Slog.w(TAG, "Could not mount OBB: " + mObbState.filename); 2182af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT); 218338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2184a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2185a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 21865af0b916f850486cff4797355bf9e7dc3352fe00Jason parks @Override 2187a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public void handleError() { 2188af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); 2189a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 2190a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root 2191a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root @Override 2192a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root public String toString() { 2193a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root StringBuilder sb = new StringBuilder(); 2194a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("UnmountObbAction{"); 2195a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append("filename="); 2196a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.filename != null ? mObbState.filename : "null"); 2197a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",force="); 2198a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mForceUnmount); 2199a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",callerUid="); 2200a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.callerUid); 2201a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(",token="); 2202a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append(mObbState.token != null ? mObbState.token.toString() : "null"); 2203735de3b38abbd6564082a819377673ee593744a6Kenny Root sb.append(",binder="); 2204af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root sb.append(mObbState.token != null ? mObbState.getBinder().toString() : "null"); 2205a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root sb.append('}'); 2206a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root return sb.toString(); 2207a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root } 220802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root } 220938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 221038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root @Override 221138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 221238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { 221338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root pw.println("Permission Denial: can't dump ActivityManager from from pid=" 221438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() 221538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root + " without permission " + android.Manifest.permission.DUMP); 221638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root return; 221738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 221838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 221938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root synchronized (mObbMounts) { 2220af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(" mObbMounts:"); 222138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root 2222af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet().iterator(); 2223af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (binders.hasNext()) { 2224af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root Entry<IBinder, List<ObbState>> e = binders.next(); 2225af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" Key="); pw.println(e.getKey().toString()); 2226af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final List<ObbState> obbStates = e.getValue(); 222738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root for (final ObbState obbState : obbStates) { 2228af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" "); pw.println(obbState.toString()); 222938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 223038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 2231af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root 2232af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(""); 2233af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.println(" mObbPathToStateMap:"); 2234af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator(); 2235af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root while (maps.hasNext()) { 2236af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root final Entry<String, ObbState> e = maps.next(); 2237af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" "); pw.print(e.getKey()); 2238af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root pw.print(" -> "); pw.println(e.getValue().toString()); 2239af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root } 224038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 224138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root } 22429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 22439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2244