MountService.java revision a80ce06d4c54e43243073f8ceff024f9dda7140e
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 19c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport com.android.server.am.ActivityManagerService; 20c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri; 27b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.os.storage.IMountService; 28b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.os.storage.IMountServiceListener; 296ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapuimport android.os.storage.IMountShutdownObserver; 30b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.os.storage.StorageResultCode; 31c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Handler; 325f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.HandlerThread; 335f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.Looper; 34c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Message; 354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehatimport android.os.RemoteException; 364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehatimport android.os.IBinder; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Environment; 38fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapuimport android.os.ServiceManager; 39207e538350665cea00e1aa70b8094beca4a34e45San Mehatimport android.os.SystemClock; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties; 41a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehatimport android.util.Slog; 4222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehatimport java.util.ArrayList; 436cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehatimport java.util.HashSet; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 46b104340496e3a531e26c8f428c808eca0e039f50San Mehat * MountService implements back-end services for platform storage 47b104340496e3a531e26c8f428c808eca0e039f50San Mehat * management. 48b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @hide - Applications should use android.os.storage.StorageManager 49b104340496e3a531e26c8f428c808eca0e039f50San Mehat * to access the MountService. 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehatclass MountService extends IMountService.Stub 5222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat implements INativeDaemonConnectorCallbacks { 53b104340496e3a531e26c8f428c808eca0e039f50San Mehat private static final boolean LOCAL_LOGD = false; 548a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu private static final boolean DEBUG_UNMOUNT = false; 558a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu private static final boolean DEBUG_EVENTS = false; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String TAG = "MountService"; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Internal vold volume state constants 614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 627fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat class VolumeState { 637fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Init = -1; 647fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int NoMedia = 0; 657fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Idle = 1; 667fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Pending = 2; 677fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Checking = 3; 687fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Mounted = 4; 697fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Unmounting = 5; 707fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Formatting = 6; 717fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Shared = 7; 727fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int SharedMnt = 8; 737fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 747fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Internal vold response code constants 774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 7822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat class VoldResponseCode { 794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 804270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 100 series - Requestion action was initiated; expect another reply 814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * before proceeding with a new command. 824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 8322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeListResult = 110; 8422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int AsecListResult = 111; 85c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat public static final int StorageUsersListResult = 112; 8622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 200 series - Requestion action has been successfully completed. 894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int ShareStatusResult = 210; 9122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int AsecPathResult = 211; 924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int ShareEnabledResult = 212; 9322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 400 series - Command was accepted, but the requested action 964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * did not take place. 974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedNoMedia = 401; 994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedMediaBlank = 402; 1004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedMediaCorrupt = 403; 1014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedVolNotMounted = 404; 102d970998b0d489774ad1c5b94b47d233912f00214San Mehat public static final int OpFailedStorageBusy = 405; 1032d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat public static final int OpFailedStorageNotFound = 406; 1044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 600 series - Unsolicited broadcasts. 1074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 10822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeStateChange = 605; 10922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int ShareAvailabilityChange = 620; 11022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeDiskInserted = 630; 11122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeDiskRemoved = 631; 11222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeBadRemoval = 632; 11322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 11422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private Context mContext; 1164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private NativeDaemonConnector mConnector; 1174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private String mLegacyState = Environment.MEDIA_REMOVED; 1184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private PackageManagerService mPms; 1194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private boolean mUmsEnabling; 1200eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Used as a lock for methods that register/unregister listeners. 1210eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu final private ArrayList<MountServiceBinderListener> mListeners = 1220eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu new ArrayList<MountServiceBinderListener>(); 1236a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private boolean mBooted = false; 1246a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private boolean mReady = false; 1256a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private boolean mSendUmsConnectedOnBoot = false; 126fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapu 1276cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat /** 1286cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat * Private hash of currently mounted secure containers. 1290eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * Used as a lock in methods to manipulate secure containers. 1306cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat */ 1310eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu final private HashSet<String> mAsecMountSet = new HashSet<String>(); 1326cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 133c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_PM_UPDATE = 1; 134c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_PM_DONE = 2; 135c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int H_UNMOUNT_MS = 3; 136c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int RETRY_UNMOUNT_DELAY = 30; // in ms 137c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu private static final int MAX_UNMOUNT_RETRIES = 4; 138c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 139c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu class UnmountCallBack { 140c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu String path; 141c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu int retries; 142c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu boolean force; 143c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 144c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack(String path, boolean force) { 145c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu retries = 0; 146c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu this.path = path; 147c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu this.force = force; 148c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 1490eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 1500eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu void handleFinished() { 151a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path); 1520eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doUnmountVolume(path, true); 1530eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 1540eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 1550eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 1560eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu class UmsEnableCallBack extends UnmountCallBack { 1570eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String method; 1580eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 1590eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu UmsEnableCallBack(String path, String method, boolean force) { 1600eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu super(path, force); 1610eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu this.method = method; 1620eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 1630eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 1640eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu @Override 1650eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu void handleFinished() { 1660eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu super.handleFinished(); 1670eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doShareUnshareVolume(path, method, true); 1680eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 169c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 170c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 1716ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu class ShutdownCallBack extends UnmountCallBack { 1726ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu IMountShutdownObserver observer; 1736ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu ShutdownCallBack(String path, IMountShutdownObserver observer) { 1746ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu super(path, true); 1756ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu this.observer = observer; 1766ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 1776ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 1786ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu @Override 1796ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu void handleFinished() { 1806ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int ret = doUnmountVolume(path, true); 1816ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (observer != null) { 1826ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu try { 1836ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu observer.onShutDownComplete(ret); 1846ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } catch (RemoteException e) { 185a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "RemoteException when shutting down"); 1866ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 1876ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 1886ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 1896ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 1906ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 1915f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler class MountServiceHandler extends Handler { 192c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>(); 193e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu boolean mUpdatingStatus = false; 1946ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu 1955f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler MountServiceHandler(Looper l) { 1965f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler super(l); 1975f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler } 1985f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler 199c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu public void handleMessage(Message msg) { 200c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu switch (msg.what) { 201c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_PM_UPDATE: { 202a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_UPDATE"); 203c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = (UnmountCallBack) msg.obj; 204c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu mForceUnmounts.add(ucb); 205a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, " registered = " + mUpdatingStatus); 2066ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Register only if needed. 207e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu if (!mUpdatingStatus) { 208a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Updating external media status on PackageManager"); 209e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mUpdatingStatus = true; 210e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(false, true); 211c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 212c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 213c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 214c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_PM_DONE: { 215a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_DONE"); 216a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Updated status. Processing requests"); 217e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mUpdatingStatus = false; 2186ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int size = mForceUnmounts.size(); 2196ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int sizeArr[] = new int[size]; 2206ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int sizeArrN = 0; 2217af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Kill processes holding references first 2227af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ActivityManagerService ams = (ActivityManagerService) 2237af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ServiceManager.getService("activity"); 2246ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu for (int i = 0; i < size; i++) { 2256ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu UnmountCallBack ucb = mForceUnmounts.get(i); 2266ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu String path = ucb.path; 2276ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu boolean done = false; 2286ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (!ucb.force) { 229c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu done = true; 230c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } else { 2316ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu int pids[] = getStorageUsers(path); 2326ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (pids == null || pids.length == 0) { 2336ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu done = true; 2346ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } else { 2356ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Eliminate system process here? 2367af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ams.killPids(pids, "unmount media"); 2377af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Confirm if file references have been freed. 2387af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu pids = getStorageUsers(path); 2397af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu if (pids == null || pids.length == 0) { 2407af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu done = true; 241c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 242c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 243c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 2447af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) { 2457af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu // Retry again 2467af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu Slog.i(TAG, "Retrying to kill storage users again"); 2477af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.sendMessageDelayed( 2487af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.obtainMessage(H_UNMOUNT_PM_DONE, 2497af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ucb.retries++), 2507af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu RETRY_UNMOUNT_DELAY); 251c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } else { 2526ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu if (ucb.retries >= MAX_UNMOUNT_RETRIES) { 2537af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu Slog.i(TAG, "Failed to unmount media inspite of " + 2547af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu MAX_UNMOUNT_RETRIES + " retries. Forcibly killing processes now"); 2556ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 2567af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu sizeArr[sizeArrN++] = i; 2577af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS, 2587af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu ucb)); 259c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 260c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 2616ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Remove already processed elements from list. 2626ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu for (int i = (sizeArrN-1); i >= 0; i--) { 2636ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu mForceUnmounts.remove(sizeArr[i]); 2646ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu } 265c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 266c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 267c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu case H_UNMOUNT_MS : { 268a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_MS"); 269c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = (UnmountCallBack) msg.obj; 2700eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu ucb.handleFinished(); 271c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu break; 272c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 273c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 274c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu } 275c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu }; 2765f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler final private HandlerThread mHandlerThread; 2775f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler final private Handler mHandler; 278c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu 279207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void waitForReady() { 280207e538350665cea00e1aa70b8094beca4a34e45San Mehat while (mReady == false) { 281207e538350665cea00e1aa70b8094beca4a34e45San Mehat for (int retries = 5; retries > 0; retries--) { 282207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (mReady) { 283207e538350665cea00e1aa70b8094beca4a34e45San Mehat return; 284207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 285207e538350665cea00e1aa70b8094beca4a34e45San Mehat SystemClock.sleep(1000); 286207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 287a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Waiting too long for mReady!"); 288207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 2891f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 2901f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat 291207e538350665cea00e1aa70b8094beca4a34e45San Mehat private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onReceive(Context context, Intent intent) { 29391c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat String action = intent.getAction(); 29491c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 29591c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { 296207e538350665cea00e1aa70b8094beca4a34e45San Mehat mBooted = true; 29722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 298c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen /* 299c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * In the simulator, we need to broadcast a volume mounted event 300c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * to make the media scanner run. 301c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen */ 302c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen if ("simulator".equals(SystemProperties.get("ro.product.device"))) { 303c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen notifyVolumeStateChange(null, "/sdcard", VolumeState.NoMedia, VolumeState.Mounted); 304c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen return; 305c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen } 306fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat new Thread() { 307fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat public void run() { 308fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat try { 309fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat String path = Environment.getExternalStorageDirectory().getPath(); 3106a254403235196692b1769d2fe281b0852c0cc25San Mehat String state = getVolumeState(path); 3116a254403235196692b1769d2fe281b0852c0cc25San Mehat 3126a254403235196692b1769d2fe281b0852c0cc25San Mehat if (state.equals(Environment.MEDIA_UNMOUNTED)) { 313fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat int rc = doMountVolume(path); 314fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat if (rc != StorageResultCode.OperationSucceeded) { 315a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Boot-time mount failed (%d)", rc)); 316fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } 3176a254403235196692b1769d2fe281b0852c0cc25San Mehat } else if (state.equals(Environment.MEDIA_SHARED)) { 3186a254403235196692b1769d2fe281b0852c0cc25San Mehat /* 3196a254403235196692b1769d2fe281b0852c0cc25San Mehat * Bootstrap UMS enabled state since vold indicates 3206a254403235196692b1769d2fe281b0852c0cc25San Mehat * the volume is shared (runtime restart while ums enabled) 3216a254403235196692b1769d2fe281b0852c0cc25San Mehat */ 3226a254403235196692b1769d2fe281b0852c0cc25San Mehat notifyVolumeStateChange(null, path, VolumeState.NoMedia, VolumeState.Shared); 323fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } 3246a254403235196692b1769d2fe281b0852c0cc25San Mehat 3256a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat /* 3266a254403235196692b1769d2fe281b0852c0cc25San Mehat * If UMS was connected on boot, send the connected event 3276a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat * now that we're up. 3286a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat */ 3296a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat if (mSendUmsConnectedOnBoot) { 3306a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat sendUmsIntent(true); 3316a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat mSendUmsConnectedOnBoot = false; 3326a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } 333fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } catch (Exception ex) { 334a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Boot-time mount exception", ex); 335fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat } 336207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 337fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat }.start(); 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private final class MountServiceBinderListener implements IBinder.DeathRecipient { 3434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final IMountServiceListener mListener; 34491c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 3454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener(IMountServiceListener listener) { 3464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListener = listener; 3474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 34891c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 34991c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 3504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void binderDied() { 351a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!"); 3524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized(mListeners) { 3534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(this); 3544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListener.asBinder().unlinkToDeath(this, 0); 35591c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 35691c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 35791c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 35891c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 3590eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private void doShareUnshareVolume(String path, String method, boolean enable) { 3604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat // TODO: Add support for multiple share methods 3614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!method.equals("ums")) { 3624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new IllegalArgumentException(String.format("Method %s not supported", method)); 3637fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 3664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(String.format( 3674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat "volume %sshare %s %s", (enable ? "" : "un"), path, method)); 3684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 369a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to share/unshare", e); 37022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 373207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void updatePublicVolumeState(String path, String state) { 3744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!path.equals(Environment.getExternalStorageDirectory().getPath())) { 375a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Multiple volumes not currently supported"); 3767fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat return; 3777fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 378b104340496e3a531e26c8f428c808eca0e039f50San Mehat 379b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (mLegacyState.equals(state)) { 380a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, String.format("Duplicate state transition (%s -> %s)", mLegacyState, state)); 381b104340496e3a531e26c8f428c808eca0e039f50San Mehat return; 382b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 3838a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // Update state on PackageManager 3848a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (Environment.MEDIA_UNMOUNTED.equals(state)) { 385e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(false, false); 3868a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } else if (Environment.MEDIA_MOUNTED.equals(state)) { 387e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(true, false); 3888a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 3894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String oldState = mLegacyState; 3904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mLegacyState = state; 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 3934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for (int i = mListeners.size() -1; i >= 0; i--) { 3944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = mListeners.get(i); 3954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 396b104340496e3a531e26c8f428c808eca0e039f50San Mehat bl.mListener.onStorageStateChanged(path, oldState, state); 3974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 398a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener dead"); 3994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(i); 4004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 401a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener failed", ex); 4024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 40722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat /** 40822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * 40922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * Callback from NativeDaemonConnector 41022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat */ 41122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public void onDaemonConnected() { 4125b77dab23469273d41f9c530d947ac055765e6eaSan Mehat /* 4135b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * Since we'll be calling back into the NativeDaemonConnector, 4145b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * we need to do our work in a new thread. 4155b77dab23469273d41f9c530d947ac055765e6eaSan Mehat */ 4167fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat new Thread() { 4177fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public void run() { 4185b77dab23469273d41f9c530d947ac055765e6eaSan Mehat /** 4195b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * Determine media state and UMS detection status 4205b77dab23469273d41f9c530d947ac055765e6eaSan Mehat */ 4215b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String path = Environment.getExternalStorageDirectory().getPath(); 4225b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String state = Environment.MEDIA_REMOVED; 4235b77dab23469273d41f9c530d947ac055765e6eaSan Mehat 4247fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat try { 4255b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String[] vols = mConnector.doListCommand( 4264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat "volume list", VoldResponseCode.VolumeListResult); 4275b77dab23469273d41f9c530d947ac055765e6eaSan Mehat for (String volstr : vols) { 4285b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String[] tok = volstr.split(" "); 4295b77dab23469273d41f9c530d947ac055765e6eaSan Mehat // FMT: <label> <mountpoint> <state> 4305b77dab23469273d41f9c530d947ac055765e6eaSan Mehat if (!tok[1].equals(path)) { 431a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, String.format( 4325b77dab23469273d41f9c530d947ac055765e6eaSan Mehat "Skipping unknown volume '%s'",tok[1])); 4335b77dab23469273d41f9c530d947ac055765e6eaSan Mehat continue; 4345b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } 4355b77dab23469273d41f9c530d947ac055765e6eaSan Mehat int st = Integer.parseInt(tok[2]); 4365b77dab23469273d41f9c530d947ac055765e6eaSan Mehat if (st == VolumeState.NoMedia) { 4375b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_REMOVED; 4385b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Idle) { 439207e538350665cea00e1aa70b8094beca4a34e45San Mehat state = Environment.MEDIA_UNMOUNTED; 4405b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Mounted) { 4415b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_MOUNTED; 442a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Media already mounted on daemon connection"); 4435b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Shared) { 4445b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_SHARED; 445a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Media shared on daemon connection"); 4465b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else { 4475b77dab23469273d41f9c530d947ac055765e6eaSan Mehat throw new Exception(String.format("Unexpected state %d", st)); 4487fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 4497fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 450c2a39471642e31d7350910612e40d078b825173aSan Mehat if (state != null) { 451a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state); 452c2a39471642e31d7350910612e40d078b825173aSan Mehat updatePublicVolumeState(path, state); 453c2a39471642e31d7350910612e40d078b825173aSan Mehat } 4545b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } catch (Exception e) { 455a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Error processing initial volume state", e); 4565b77dab23469273d41f9c530d947ac055765e6eaSan Mehat updatePublicVolumeState(path, Environment.MEDIA_REMOVED); 4577fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 4587fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 4597fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat try { 460207e538350665cea00e1aa70b8094beca4a34e45San Mehat boolean avail = doGetShareMethodAvailable("ums"); 4617fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat notifyShareAvailabilityChange("ums", avail); 4627fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } catch (Exception ex) { 463a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Failed to get share availability"); 4647fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 465207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 466207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Now that we've done our initialization, release 467207e538350665cea00e1aa70b8094beca4a34e45San Mehat * the hounds! 468207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 469207e538350665cea00e1aa70b8094beca4a34e45San Mehat mReady = true; 4707fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 4717fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat }.start(); 4727fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 4737fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 47422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat /** 47522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * Callback from NativeDaemonConnector 47622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat */ 47722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public boolean onEvent(int code, String raw, String[] cooked) { 4784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Intent in = null; 4794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 4808a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (DEBUG_EVENTS) { 4818a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu StringBuilder builder = new StringBuilder(); 4828a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append("onEvent::"); 4838a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" raw= " + raw); 4848a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (cooked != null) { 4858a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" cooked = " ); 4868a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu for (String str : cooked) { 4878a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu builder.append(" " + str); 4888a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 4898a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 490a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, builder.toString()); 4918a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 49222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat if (code == VoldResponseCode.VolumeStateChange) { 4934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 4944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * One of the volumes we're managing has changed state. 4954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Format: "NNN Volume <label> <path> state changed 4964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * from <old_#> (<old_str>) to <new_#> (<new_str>)" 4974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 49822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat notifyVolumeStateChange( 49922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat cooked[2], cooked[3], Integer.parseInt(cooked[7]), 50022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat Integer.parseInt(cooked[10])); 50122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else if (code == VoldResponseCode.ShareAvailabilityChange) { 50222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Share method <method> now <available|unavailable> 50322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat boolean avail = false; 50422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat if (cooked[5].equals("available")) { 50522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat avail = true; 50622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 50722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat notifyShareAvailabilityChange(cooked[3], avail); 5084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if ((code == VoldResponseCode.VolumeDiskInserted) || 5094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat (code == VoldResponseCode.VolumeDiskRemoved) || 5104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat (code == VoldResponseCode.VolumeBadRemoval)) { 51122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>) 51222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>) 51322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>) 5144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final String label = cooked[2]; 5154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final String path = cooked[3]; 5164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int major = -1; 5174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int minor = -1; 5184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 5194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 5204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String devComp = cooked[6].substring(1, cooked[6].length() -1); 5214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String[] devTok = devComp.split(":"); 5224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat major = Integer.parseInt(devTok[0]); 5234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat minor = Integer.parseInt(devTok[1]); 5244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 525a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to parse major/minor", ex); 5264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 5274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 5284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (code == VoldResponseCode.VolumeDiskInserted) { 5294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat new Thread() { 5304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void run() { 5314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 5324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int rc; 533b104340496e3a531e26c8f428c808eca0e039f50San Mehat if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { 534a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, String.format("Insertion mount failed (%d)", rc)); 5354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 5364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 537a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Failed to mount media on insertion", ex); 5384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 5394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 5404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat }.start(); 5414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (code == VoldResponseCode.VolumeDiskRemoved) { 5424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 5434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * This event gets trumped if we're already in BAD_REMOVAL state 5444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 5454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) { 5464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return true; 5474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 5484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 549a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first"); 5504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 5514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); 5524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 5534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 554a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed"); 5554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_REMOVED); 5564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_REMOVED, Uri.parse("file://" + path)); 5574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (code == VoldResponseCode.VolumeBadRemoval) { 558a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first"); 5594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 5604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 5614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); 5624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 5634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 564a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal"); 5654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL); 5664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL, Uri.parse("file://" + path)); 5674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else { 568a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Unknown code {%d}", code)); 5694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 57022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else { 57122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat return false; 57222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 5734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 5744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (in != null) { 5754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 5765f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler } 5775f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler return true; 57822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 57922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 580207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void notifyVolumeStateChange(String label, String path, int oldState, int newState) { 5814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String vs = getVolumeState(path); 582a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChanged::" + vs); 5834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 5844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Intent in = null; 5857fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 586bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood if (oldState == VolumeState.Shared && newState != oldState) { 587a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent"); 588bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_UNSHARED, 589bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood Uri.parse("file://" + path))); 590bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood } 591bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood 5927fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat if (newState == VolumeState.Init) { 5937fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.NoMedia) { 5947fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat // NoMedia is handled via Disk Remove events 5957fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Idle) { 5965fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat /* 5975fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or 5985fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat * if we're in the process of enabling UMS 5995fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat */ 6004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!vs.equals( 6014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Environment.MEDIA_BAD_REMOVAL) && !vs.equals( 6024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Environment.MEDIA_NOFS) && !vs.equals( 6030eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) { 604a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable"); 6054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 6064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); 6077fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6087fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Pending) { 6097fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Checking) { 610a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking"); 6114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_CHECKING); 6124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_CHECKING, Uri.parse("file://" + path)); 6137fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Mounted) { 614a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted"); 6154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_MOUNTED); 6164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + path)); 6174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in.putExtra("read-only", false); 6187fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Unmounting) { 6194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_EJECT, Uri.parse("file://" + path)); 6207fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Formatting) { 6217fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Shared) { 622a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted"); 6234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 6244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 6254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); 6264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 6274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 628a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared"); 6294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_SHARED); 6304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_SHARED, Uri.parse("file://" + path)); 631a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent"); 6327fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.SharedMnt) { 633a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Live shared mounts not supported yet!"); 6344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return; 6357fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else { 636a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Unhandled VolumeState {" + newState + "}"); 6377fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6387fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 6394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (in != null) { 6404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 644207e538350665cea00e1aa70b8094beca4a34e45San Mehat private boolean doGetShareMethodAvailable(String method) { 645a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root try { 646a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root ArrayList<String> rsp = mConnector.doCommand("share status " + method); 647a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } catch (NativeDaemonConnectorException ex) { 648a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root Slog.e(TAG, "Failed to determine whether share method " + method + " is available."); 649a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return false; 650a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } 651207e538350665cea00e1aa70b8094beca4a34e45San Mehat 652207e538350665cea00e1aa70b8094beca4a34e45San Mehat for (String line : rsp) { 653a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root String[] tok = line.split(" "); 654a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root if (tok.length < 3) { 655a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root Slog.e(TAG, "Malformed response to share status " + method); 656a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return false; 657a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } 658a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root 659207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code; 660207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 661207e538350665cea00e1aa70b8094beca4a34e45San Mehat code = Integer.parseInt(tok[0]); 662207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NumberFormatException nfe) { 663a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Error parsing code %s", tok[0])); 664207e538350665cea00e1aa70b8094beca4a34e45San Mehat return false; 665207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 666207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.ShareStatusResult) { 667207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (tok[2].equals("available")) 668207e538350665cea00e1aa70b8094beca4a34e45San Mehat return true; 669207e538350665cea00e1aa70b8094beca4a34e45San Mehat return false; 670207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 671a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Unexpected response code %d", code)); 672207e538350665cea00e1aa70b8094beca4a34e45San Mehat return false; 673207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 674207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 675a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Got an empty response"); 676207e538350665cea00e1aa70b8094beca4a34e45San Mehat return false; 677207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 678207e538350665cea00e1aa70b8094beca4a34e45San Mehat 679207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doMountVolume(String path) { 680b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 681207e538350665cea00e1aa70b8094beca4a34e45San Mehat 682a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path); 683207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 684207e538350665cea00e1aa70b8094beca4a34e45San Mehat mConnector.doCommand(String.format("volume mount %s", path)); 685207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 686207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 687207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Mount failed for some reason 688207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 689207e538350665cea00e1aa70b8094beca4a34e45San Mehat Intent in = null; 690207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 691207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedNoMedia) { 692207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 693207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Attempt to mount but no media inserted 694207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 695b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedNoMedia; 696207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaBlank) { 697a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs"); 698207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 699207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Media is blank or does not contain a supported filesystem 700207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 701207e538350665cea00e1aa70b8094beca4a34e45San Mehat updatePublicVolumeState(path, Environment.MEDIA_NOFS); 702207e538350665cea00e1aa70b8094beca4a34e45San Mehat in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path)); 703b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedMediaBlank; 704207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { 705a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state media corrupt"); 706207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 707207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Volume consistency check failed 708207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 709207e538350665cea00e1aa70b8094beca4a34e45San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE); 710207e538350665cea00e1aa70b8094beca4a34e45San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path)); 711b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedMediaCorrupt; 712207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 713b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 714207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 715207e538350665cea00e1aa70b8094beca4a34e45San Mehat 716207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 717207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Send broadcast intent (if required for the failure) 718207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 719207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (in != null) { 720207e538350665cea00e1aa70b8094beca4a34e45San Mehat mContext.sendBroadcast(in); 721207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 722207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 723207e538350665cea00e1aa70b8094beca4a34e45San Mehat 724207e538350665cea00e1aa70b8094beca4a34e45San Mehat return rc; 725207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 726207e538350665cea00e1aa70b8094beca4a34e45San Mehat 727c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu /* 728c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * If force is not set, we do not unmount if there are 729c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * processes holding references to the volume about to be unmounted. 730c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * If force is set, all the processes holding references need to be 731c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * killed via the ActivityManager before actually unmounting the volume. 732c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * This might even take a while and might be retried after timed delays 733c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * to make sure we dont end up in an instable state and kill some core 734c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu * processes. 735c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu */ 736d970998b0d489774ad1c5b94b47d233912f00214San Mehat private int doUnmountVolume(String path, boolean force) { 73759443a673a736978361dc341f41ce4e9dae053a0San Mehat if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) { 738207e538350665cea00e1aa70b8094beca4a34e45San Mehat return VoldResponseCode.OpFailedVolNotMounted; 739207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 740c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu // Redundant probably. But no harm in updating state again. 741e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mPms.updateExternalMediaStatus(false, false); 742207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 743d970998b0d489774ad1c5b94b47d233912f00214San Mehat mConnector.doCommand(String.format( 744d970998b0d489774ad1c5b94b47d233912f00214San Mehat "volume unmount %s%s", path, (force ? " force" : ""))); 745e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu // We unmounted the volume. None of the asec containers are available now. 746e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu synchronized (mAsecMountSet) { 747e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mAsecMountSet.clear(); 748e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu } 749b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationSucceeded; 750207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 751207e538350665cea00e1aa70b8094beca4a34e45San Mehat // Don't worry about mismatch in PackageManager since the 752207e538350665cea00e1aa70b8094beca4a34e45San Mehat // call back will handle the status changes any way. 753207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 754207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedVolNotMounted) { 755a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageNotMounted; 756d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else if (code == VoldResponseCode.OpFailedStorageBusy) { 757d970998b0d489774ad1c5b94b47d233912f00214San Mehat return StorageResultCode.OperationFailedStorageBusy; 758207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 759b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedInternalError; 760207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 761207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 762207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 763207e538350665cea00e1aa70b8094beca4a34e45San Mehat 764207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doFormatVolume(String path) { 765207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 766207e538350665cea00e1aa70b8094beca4a34e45San Mehat String cmd = String.format("volume format %s", path); 767207e538350665cea00e1aa70b8094beca4a34e45San Mehat mConnector.doCommand(cmd); 768b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationSucceeded; 769207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 770207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 771207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedNoMedia) { 772b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedNoMedia; 773207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { 774b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedMediaCorrupt; 775207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 776b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedInternalError; 777207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 778207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 779207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 780207e538350665cea00e1aa70b8094beca4a34e45San Mehat 781b104340496e3a531e26c8f428c808eca0e039f50San Mehat private boolean doGetVolumeShared(String path, String method) { 782b104340496e3a531e26c8f428c808eca0e039f50San Mehat String cmd = String.format("volume shared %s %s", path, method); 783a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root ArrayList<String> rsp; 784a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root 785a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root try { 786a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root rsp = mConnector.doCommand(cmd); 787a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } catch (NativeDaemonConnectorException ex) { 788a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root Slog.e(TAG, "Failed to read response to volume shared " + path + " " + method); 789a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return false; 790a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } 791b104340496e3a531e26c8f428c808eca0e039f50San Mehat 792b104340496e3a531e26c8f428c808eca0e039f50San Mehat for (String line : rsp) { 793a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root String[] tok = line.split(" "); 794a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root if (tok.length < 3) { 795a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root Slog.e(TAG, "Malformed response to volume shared " + path + " " + method + " command"); 796a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return false; 797a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root } 798a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root 799b104340496e3a531e26c8f428c808eca0e039f50San Mehat int code; 800b104340496e3a531e26c8f428c808eca0e039f50San Mehat try { 801b104340496e3a531e26c8f428c808eca0e039f50San Mehat code = Integer.parseInt(tok[0]); 802b104340496e3a531e26c8f428c808eca0e039f50San Mehat } catch (NumberFormatException nfe) { 803a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Error parsing code %s", tok[0])); 804b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 805b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 806b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (code == VoldResponseCode.ShareEnabledResult) { 807a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root return "enabled".equals(tok[2]); 808b104340496e3a531e26c8f428c808eca0e039f50San Mehat } else { 809a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Unexpected response code %d", code)); 810b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 811b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 812b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 813a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Got an empty response"); 814b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 815b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 816b104340496e3a531e26c8f428c808eca0e039f50San Mehat 817207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void notifyShareAvailabilityChange(String method, final boolean avail) { 8187fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat if (!method.equals("ums")) { 819a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Ignoring unsupported share method {" + method + "}"); 8207fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat return; 8217fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 8221f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat 8234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 8244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for (int i = mListeners.size() -1; i >= 0; i--) { 8254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = mListeners.get(i); 8261f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat try { 827b104340496e3a531e26c8f428c808eca0e039f50San Mehat bl.mListener.onUsbMassStorageConnectionChanged(avail); 8284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 829a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener dead"); 8304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(i); 8311f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } catch (Exception ex) { 832a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Listener failed", ex); 8331f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 8341f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 8354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 8367fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 837207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (mBooted == true) { 8386a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat sendUmsIntent(avail); 8396a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } else { 8406a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat mSendUmsConnectedOnBoot = avail; 8411f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 8422fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat 8432fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat final String path = Environment.getExternalStorageDirectory().getPath(); 8442fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat if (avail == false && getVolumeState(path).equals(Environment.MEDIA_SHARED)) { 8452fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat /* 8462fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat * USB mass storage disconnected while enabled 8472fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat */ 8482fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat new Thread() { 8492fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat public void run() { 8502fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat try { 8512fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat int rc; 852a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Disabling UMS after cable disconnect"); 8532fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat doShareUnshareVolume(path, "ums", false); 8542fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { 855a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format( 8562fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat "Failed to remount {%s} on UMS enabled-disconnect (%d)", 8572fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat path, rc)); 8582fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 8592fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } catch (Exception ex) { 860a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "Failed to mount media on UMS enabled-disconnect", ex); 8612fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 8622fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 8632fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat }.start(); 8642fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat } 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8676a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat private void sendUmsIntent(boolean c) { 8686a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat mContext.sendBroadcast( 8696a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat new Intent((c ? Intent.ACTION_UMS_CONNECTED : Intent.ACTION_UMS_DISCONNECTED))); 8706a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat } 8716a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat 872207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void validatePermission(String perm) { 8734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) { 8744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new SecurityException(String.format("Requires %s permission", perm)); 8754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 8767fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 8777fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 879207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Constructs a new MountService instance 880207e538350665cea00e1aa70b8094beca4a34e45San Mehat * 881207e538350665cea00e1aa70b8094beca4a34e45San Mehat * @param context Binder context for this service 882207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 883207e538350665cea00e1aa70b8094beca4a34e45San Mehat public MountService(Context context) { 884207e538350665cea00e1aa70b8094beca4a34e45San Mehat mContext = context; 885207e538350665cea00e1aa70b8094beca4a34e45San Mehat 886207e538350665cea00e1aa70b8094beca4a34e45San Mehat // XXX: This will go away soon in favor of IMountServiceObserver 887207e538350665cea00e1aa70b8094beca4a34e45San Mehat mPms = (PackageManagerService) ServiceManager.getService("package"); 888207e538350665cea00e1aa70b8094beca4a34e45San Mehat 889207e538350665cea00e1aa70b8094beca4a34e45San Mehat mContext.registerReceiver(mBroadcastReceiver, 890207e538350665cea00e1aa70b8094beca4a34e45San Mehat new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); 891207e538350665cea00e1aa70b8094beca4a34e45San Mehat 8925f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandlerThread = new HandlerThread("MountService"); 8935f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandlerThread.start(); 8945f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler mHandler = new MountServiceHandler(mHandlerThread.getLooper()); 8955f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler 896c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen /* 897c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * Vold does not run in the simulator, so pretend the connector thread 898c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen * ran and did its thing. 899c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen */ 900c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen if ("simulator".equals(SystemProperties.get("ro.product.device"))) { 901c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen mReady = true; 902c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen mUmsEnabling = true; 903c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen return; 904c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen } 905c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen 906207e538350665cea00e1aa70b8094beca4a34e45San Mehat mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector"); 907207e538350665cea00e1aa70b8094beca4a34e45San Mehat mReady = false; 908207e538350665cea00e1aa70b8094beca4a34e45San Mehat Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName()); 909207e538350665cea00e1aa70b8094beca4a34e45San Mehat thread.start(); 910207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 911207e538350665cea00e1aa70b8094beca4a34e45San Mehat 912207e538350665cea00e1aa70b8094beca4a34e45San Mehat /** 9134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Exposed API calls below here 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9157fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 9164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void registerListener(IMountServiceListener listener) { 9174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 9184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = new MountServiceBinderListener(listener); 9194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 9204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat listener.asBinder().linkToDeath(bl, 0); 9214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.add(bl); 9224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 923a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to link to listener death"); 9244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 9257fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void unregisterListener(IMountServiceListener listener) { 9294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 9304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for(MountServiceBinderListener bl : mListeners) { 9314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (bl.mListener == listener) { 9324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(mListeners.indexOf(bl)); 9334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return; 9344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 9354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9396ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu public void shutdown(final IMountShutdownObserver observer) { 9404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.SHUTDOWN); 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 942a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.i(TAG, "Shutting down"); 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String path = Environment.getExternalStorageDirectory().getPath(); 9454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String state = getVolumeState(path); 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (state.equals(Environment.MEDIA_SHARED)) { 9484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 9494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * If the media is currently shared, unshare it. 9504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * XXX: This is still dangerous!. We should not 9514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * be rebooting at *all* if UMS is enabled, since 9524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * the UMS host could have dirty FAT cache entries 9534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * yet to flush. 9544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 9550eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu setUsbMassStorageEnabled(false); 9564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (state.equals(Environment.MEDIA_CHECKING)) { 9574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 9584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * If the media is being checked, then we need to wait for 9594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * it to complete before being able to proceed. 9604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 9614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat // XXX: @hackbod - Should we disable the ANR timer here? 9624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int retries = 30; 9634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) { 9644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 9654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Thread.sleep(1000); 9664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (InterruptedException iex) { 967a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Interrupted while waiting for media", iex); 9684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat break; 9694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 9704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat state = Environment.getExternalStorageState(); 9714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 9724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (retries == 0) { 973a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Timed out waiting for media to check"); 9744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 9757fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 9767fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 9774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (state.equals(Environment.MEDIA_MOUNTED)) { 9786ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu // Post a unmount message. 9796ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu ShutdownCallBack ucb = new ShutdownCallBack(path, observer); 9806ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb)); 9811f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9840eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private boolean getUmsEnabling() { 9850eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu synchronized (mListeners) { 9860eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu return mUmsEnabling; 9870eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 9880eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 9890eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 9900eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu private void setUmsEnabling(boolean enable) { 9910eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu synchronized (mListeners) { 9920eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu mUmsEnabling = true; 9930eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 9940eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 9950eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 996b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageConnected() { 997207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 9987fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 9990eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (getUmsEnabling()) { 1000b104340496e3a531e26c8f428c808eca0e039f50San Mehat return true; 1001b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1002b104340496e3a531e26c8f428c808eca0e039f50San Mehat return doGetShareMethodAvailable("ums"); 10034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10050eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu public void setUsbMassStorageEnabled(boolean enable) { 1006207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 10070eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 10080eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu 10090eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // TODO: Add support for multiple share methods 1010b104340496e3a531e26c8f428c808eca0e039f50San Mehat 10110eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 10120eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * If the volume is mounted and we're enabling then unmount it 10130eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 10140eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String path = Environment.getExternalStorageDirectory().getPath(); 10150eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String vs = getVolumeState(path); 10160eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu String method = "ums"; 10170eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (enable && vs.equals(Environment.MEDIA_MOUNTED)) { 10180eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Override for isUsbMassStorageEnabled() 10190eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu setUmsEnabling(enable); 10200eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true); 10210eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb)); 10220eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu // Clear override 10230eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu setUmsEnabling(false); 10240eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 10250eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 10260eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * If we disabled UMS then mount the volume 10270eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 10280eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (!enable) { 10290eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu doShareUnshareVolume(path, method, enable); 10300eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu if (doMountVolume(path) != StorageResultCode.OperationSucceeded) { 1031a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to remount " + path + 10320eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu " after disabling share method " + method); 10330eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu /* 10340eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * Even though the mount failed, the unshare didn't so don't indicate an error. 10350eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * The mountVolume() call will have set the storage state and sent the necessary 10360eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu * broadcasts. 10370eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu */ 10380eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 10390eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu } 10404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1042b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageEnabled() { 1043207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1044b104340496e3a531e26c8f428c808eca0e039f50San Mehat return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums"); 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * @return state of the volume at the specified mount point 10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String getVolumeState(String mountPoint) { 10514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 10524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * XXX: Until we have multiple volume discovery, just hardwire 10534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * this to /sdcard 10544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 10554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) { 1056a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume"); 10574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new IllegalArgumentException(); 10584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 10594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 10604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return mLegacyState; 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 10634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int mountVolume(String path) { 10644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1066207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1067207e538350665cea00e1aa70b8094beca4a34e45San Mehat return doMountVolume(path); 10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1070c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu public void unmountVolume(String path, boolean force) { 10714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1072207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10748a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu String volState = getVolumeState(path); 1075a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path + " force = " + force); 10768a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu if (Environment.MEDIA_UNMOUNTED.equals(volState) || 10778a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_REMOVED.equals(volState) || 10788a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_SHARED.equals(volState) || 10798a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu Environment.MEDIA_UNMOUNTABLE.equals(volState)) { 10808a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // Media already unmounted or cannot be unmounted. 10818a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu // TODO return valid return code when adding observer call back. 10828a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu return; 10838a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu } 1084c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu UnmountCallBack ucb = new UnmountCallBack(path, force); 1085c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb)); 10864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int formatVolume(String path) { 10894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); 1090207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1092207e538350665cea00e1aa70b8094beca4a34e45San Mehat return doFormatVolume(path); 10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10943697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1095c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat public int []getStorageUsers(String path) { 1096c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1097c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat waitForReady(); 1098c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat try { 1099c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat String[] r = mConnector.doListCommand( 1100c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat String.format("storage users %s", path), 1101c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat VoldResponseCode.StorageUsersListResult); 1102c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat // FMT: <pid> <process name> 1103c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat int[] data = new int[r.length]; 1104c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat for (int i = 0; i < r.length; i++) { 1105c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat String []tok = r[i].split(" "); 1106c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat try { 1107c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat data[i] = Integer.parseInt(tok[0]); 1108c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } catch (NumberFormatException nfe) { 1109a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, String.format("Error parsing pid %s", tok[0])); 1110c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return new int[0]; 1111c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1112c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1113c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return data; 1114c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } catch (NativeDaemonConnectorException e) { 1115a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.e(TAG, "Failed to retrieve storage users list", e); 1116c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat return new int[0]; 1117c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1118c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat } 1119c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat 1120b104340496e3a531e26c8f428c808eca0e039f50San Mehat private void warnOnNotMounted() { 1121b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 1122a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat Slog.w(TAG, "getSecureContainerList() called when storage not mounted"); 1123b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1124b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 1125b104340496e3a531e26c8f428c808eca0e039f50San Mehat 11264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String[] getSecureContainerList() { 11274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 1128207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1129b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1130f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 11314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 11324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult); 11334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 11344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return new String[0]; 113502735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 11363697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 11373697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 11384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int createSecureContainer(String id, int sizeMb, String fstype, 11394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String key, int ownerUid) { 11404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_CREATE); 1141207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1142b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 11434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1144b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 11454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String cmd = String.format("asec create %s %d %s %s %d", id, sizeMb, fstype, key, ownerUid); 11464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 11474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 11484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1149b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 115002735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1151a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1152a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (rc == StorageResultCode.OperationSucceeded) { 1153a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1154a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat mAsecMountSet.add(id); 1155a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1156a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 11574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 11583697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 11593697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 11604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int finalizeSecureContainer(String id) { 11614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_CREATE); 1162b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 11634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1164b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 11654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 11664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(String.format("asec finalize %s", id)); 1167a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat /* 1168a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat * Finalization does a remount, so no need 1169a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat * to update mAsecMountSet 1170a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat */ 11714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1172b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 117302735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 11744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 11753697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 11763697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1177d970998b0d489774ad1c5b94b47d233912f00214San Mehat public int destroySecureContainer(String id, boolean force) { 11784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_DESTROY); 1179207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1180b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1181f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 1182b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 11834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1184d970998b0d489774ad1c5b94b47d233912f00214San Mehat mConnector.doCommand(String.format("asec destroy %s%s", id, (force ? " force" : ""))); 11854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1186d970998b0d489774ad1c5b94b47d233912f00214San Mehat int code = e.getCode(); 1187d970998b0d489774ad1c5b94b47d233912f00214San Mehat if (code == VoldResponseCode.OpFailedStorageBusy) { 1188d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedStorageBusy; 1189d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else { 1190d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedInternalError; 1191d970998b0d489774ad1c5b94b47d233912f00214San Mehat } 119202735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1193a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1194a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (rc == StorageResultCode.OperationSucceeded) { 1195a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1196a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (mAsecMountSet.contains(id)) { 1197a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat mAsecMountSet.remove(id); 1198a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1199a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1200a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1201a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 12024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 12033697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 12043697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 12054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int mountSecureContainer(String id, String key, int ownerUid) { 12064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 1207207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1208b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 12094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1210a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 1211a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (mAsecMountSet.contains(id)) { 1212a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageMounted; 1213a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1214a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1215a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1216b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 12174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String cmd = String.format("asec mount %s %s %d", id, key, ownerUid); 12184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 12194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 12204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1221f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root int code = e.getCode(); 1222f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root if (code != VoldResponseCode.OpFailedStorageBusy) { 1223f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root rc = StorageResultCode.OperationFailedInternalError; 1224f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root } 122502735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 12266cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 12276cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (rc == StorageResultCode.OperationSucceeded) { 12286cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 12296cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat mAsecMountSet.add(id); 12306cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 12316cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 12324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 12333697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 12343697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 1235d970998b0d489774ad1c5b94b47d233912f00214San Mehat public int unmountSecureContainer(String id, boolean force) { 12364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 1237207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1238b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 12394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 12406cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 12416cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (!mAsecMountSet.contains(id)) { 1242a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageNotMounted; 12436cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 12446cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 12456cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 1246b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 1247d970998b0d489774ad1c5b94b47d233912f00214San Mehat String cmd = String.format("asec unmount %s%s", id, (force ? " force" : "")); 12484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 12494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 12504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1251d970998b0d489774ad1c5b94b47d233912f00214San Mehat int code = e.getCode(); 1252d970998b0d489774ad1c5b94b47d233912f00214San Mehat if (code == VoldResponseCode.OpFailedStorageBusy) { 1253d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedStorageBusy; 1254d970998b0d489774ad1c5b94b47d233912f00214San Mehat } else { 1255d970998b0d489774ad1c5b94b47d233912f00214San Mehat rc = StorageResultCode.OperationFailedInternalError; 1256d970998b0d489774ad1c5b94b47d233912f00214San Mehat } 125702735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 12586cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 12596cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (rc == StorageResultCode.OperationSucceeded) { 12606cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 12616cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat mAsecMountSet.remove(id); 12626cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 12636cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 12644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 12659dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat } 12669dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat 12676cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat public boolean isSecureContainerMounted(String id) { 12686cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 12696cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat waitForReady(); 12706cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat warnOnNotMounted(); 12716cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 12726cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 12736cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat return mAsecMountSet.contains(id); 12746cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 12756cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 12766cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 12774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int renameSecureContainer(String oldId, String newId) { 12784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_RENAME); 1279207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1280b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 12814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1282a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 128385451ee15fdf6cae371dc3005441988c7d426401San Mehat /* 128485451ee15fdf6cae371dc3005441988c7d426401San Mehat * Because a mounted container has active internal state which cannot be 128585451ee15fdf6cae371dc3005441988c7d426401San Mehat * changed while active, we must ensure both ids are not currently mounted. 128685451ee15fdf6cae371dc3005441988c7d426401San Mehat */ 128785451ee15fdf6cae371dc3005441988c7d426401San Mehat if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) { 1288a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageMounted; 1289a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1290a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 1291a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 1292b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 12934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String cmd = String.format("asec rename %s %s", oldId, newId); 12944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 12954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 12964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1297b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 129802735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 1299a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 13004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 130145f61040823d8c442838f75cde8760f236603daeSan Mehat } 130245f61040823d8c442838f75cde8760f236603daeSan Mehat 13034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String getSecureContainerPath(String id) { 13044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 1305207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 1306b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 1307f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 13082d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat try { 13092d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat ArrayList<String> rsp = mConnector.doCommand(String.format("asec path %s", id)); 13102d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat String []tok = rsp.get(0).split(" "); 131122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat int code = Integer.parseInt(tok[0]); 13122d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat if (code != VoldResponseCode.AsecPathResult) { 13132d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat throw new IllegalStateException(String.format("Unexpected response code %d", code)); 13142d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat } 13152d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat return tok[1]; 13162d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat } catch (NativeDaemonConnectorException e) { 13172d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat int code = e.getCode(); 13182d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat if (code == VoldResponseCode.OpFailedStorageNotFound) { 13192d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat throw new IllegalArgumentException(String.format("Container '%s' not found", id)); 132022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else { 13212d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat throw new IllegalStateException(String.format("Unexpected response code %d", code)); 132222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 132322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 132422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 1325e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu 1326e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu public void finishMediaUpdate() { 1327e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE); 1328e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu } 13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1331