MountService.java revision a181b21305e0bcf171e2112a3ca5c08eb4fd2434
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 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri; 26b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.os.storage.IMountService; 27b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.os.storage.IMountServiceListener; 28b104340496e3a531e26c8f428c808eca0e039f50San Mehatimport android.os.storage.StorageResultCode; 294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehatimport android.os.RemoteException; 304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehatimport android.os.IBinder; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Environment; 32fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapuimport android.os.ServiceManager; 33207e538350665cea00e1aa70b8094beca4a34e45San Mehatimport android.os.SystemClock; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.UEventObserver; 361f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehatimport android.os.Handler; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 3922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehatimport java.util.ArrayList; 406cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehatimport java.util.HashSet; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileReader; 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; 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String TAG = "MountService"; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Internal vold volume state constants 594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 607fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat class VolumeState { 617fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Init = -1; 627fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int NoMedia = 0; 637fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Idle = 1; 647fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Pending = 2; 657fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Checking = 3; 667fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Mounted = 4; 677fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Unmounting = 5; 687fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Formatting = 6; 697fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int Shared = 7; 707fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public static final int SharedMnt = 8; 717fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 727fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Internal vold response code constants 754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 7622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat class VoldResponseCode { 774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 100 series - Requestion action was initiated; expect another reply 794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * before proceeding with a new command. 804270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 8122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeListResult = 110; 8222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int AsecListResult = 111; 8322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 200 series - Requestion action has been successfully completed. 864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int ShareStatusResult = 210; 8822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int AsecPathResult = 211; 894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int ShareEnabledResult = 212; 9022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 400 series - Command was accepted, but the requested action 934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * did not take place. 944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedNoMedia = 401; 964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedMediaBlank = 402; 974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedMediaCorrupt = 403; 984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedVolNotMounted = 404; 994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public static final int OpFailedVolBusy = 405; 1004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 1014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 1024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * 600 series - Unsolicited broadcasts. 1034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 10422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeStateChange = 605; 10522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int ShareAvailabilityChange = 620; 10622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeDiskInserted = 630; 10722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeDiskRemoved = 631; 10822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public static final int VolumeBadRemoval = 632; 10922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 11022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 1114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private Context mContext; 1124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private NativeDaemonConnector mConnector; 1134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private String mLegacyState = Environment.MEDIA_REMOVED; 1144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private PackageManagerService mPms; 1154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private boolean mUmsEnabling; 1164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private ArrayList<MountServiceBinderListener> mListeners; 117207e538350665cea00e1aa70b8094beca4a34e45San Mehat private boolean mBooted; 118207e538350665cea00e1aa70b8094beca4a34e45San Mehat private boolean mReady; 119fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapu 1206cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat /** 1216cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat * Private hash of currently mounted secure containers. 1226cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat */ 1236cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat private HashSet<String> mAsecMountSet = new HashSet<String>(); 1246cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 125207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void waitForReady() { 126207e538350665cea00e1aa70b8094beca4a34e45San Mehat while (mReady == false) { 127207e538350665cea00e1aa70b8094beca4a34e45San Mehat for (int retries = 5; retries > 0; retries--) { 128207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (mReady) { 129207e538350665cea00e1aa70b8094beca4a34e45San Mehat return; 130207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 131207e538350665cea00e1aa70b8094beca4a34e45San Mehat SystemClock.sleep(1000); 132207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 133207e538350665cea00e1aa70b8094beca4a34e45San Mehat Log.w(TAG, "Waiting too long for mReady!"); 134207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1351f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 1361f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat 137207e538350665cea00e1aa70b8094beca4a34e45San Mehat private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onReceive(Context context, Intent intent) { 13991c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat String action = intent.getAction(); 14091c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 14191c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { 142207e538350665cea00e1aa70b8094beca4a34e45San Mehat mBooted = true; 14322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 144207e538350665cea00e1aa70b8094beca4a34e45San Mehat String path = Environment.getExternalStorageDirectory().getPath(); 145207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (getVolumeState(path).equals(Environment.MEDIA_UNMOUNTED)) { 146207e538350665cea00e1aa70b8094beca4a34e45San Mehat int rc = doMountVolume(path); 147b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (rc != StorageResultCode.OperationSucceeded) { 148207e538350665cea00e1aa70b8094beca4a34e45San Mehat Log.e(TAG, String.format("Boot-time mount failed (%d)", rc)); 149207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 150207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat private final class MountServiceBinderListener implements IBinder.DeathRecipient { 1564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final IMountServiceListener mListener; 15791c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 1584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener(IMountServiceListener listener) { 1594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListener = listener; 1604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 16191c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 16291c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 1634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void binderDied() { 164b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (LOCAL_LOGD) Log.d(TAG, "An IMountServiceListener has died!"); 1654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized(mListeners) { 1664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(this); 1674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListener.asBinder().unlinkToDeath(this, 0); 16891c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 16991c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 17091c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat } 17191c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat 172207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doShareUnshareVolume(String path, String method, boolean enable) { 1734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat // TODO: Add support for multiple share methods 1764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!method.equals("ums")) { 1774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new IllegalArgumentException(String.format("Method %s not supported", method)); 1787fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1807fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat /* 1814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * If the volume is mounted and we're enabling then unmount it 1827fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat */ 1834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String vs = getVolumeState(path); 1844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (enable && vs.equals(Environment.MEDIA_MOUNTED)) { 185b104340496e3a531e26c8f428c808eca0e039f50San Mehat mUmsEnabling = enable; // Override for isUsbMassStorageEnabled() 18659443a673a736978361dc341f41ce4e9dae053a0San Mehat int rc = doUnmountVolume(path); 187b104340496e3a531e26c8f428c808eca0e039f50San Mehat mUmsEnabling = false; // Clear override 18859443a673a736978361dc341f41ce4e9dae053a0San Mehat if (rc != StorageResultCode.OperationSucceeded) { 18959443a673a736978361dc341f41ce4e9dae053a0San Mehat Log.e(TAG, String.format("Failed to unmount before enabling UMS (%d)", rc)); 19059443a673a736978361dc341f41ce4e9dae053a0San Mehat return rc; 19159443a673a736978361dc341f41ce4e9dae053a0San Mehat } 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 1954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(String.format( 1964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat "volume %sshare %s %s", (enable ? "" : "un"), path, method)); 1974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 1984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.e(TAG, "Failed to share/unshare", e); 199b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedInternalError; 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 2034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * If we disabled UMS then mount the volume 2044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 2054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!enable) { 206b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (doMountVolume(path) != StorageResultCode.OperationSucceeded) { 2074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.e(TAG, String.format( 2084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat "Failed to remount %s after disabling share method %s", path, method)); 2094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 2104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Even though the mount failed, the unshare didn't so don't indicate an error. 2114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * The mountVolume() call will have set the storage state and sent the necessary 2124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * broadcasts. 2134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 21422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 21522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 21622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 217b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationSucceeded; 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 220207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void updatePublicVolumeState(String path, String state) { 2214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!path.equals(Environment.getExternalStorageDirectory().getPath())) { 2227fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat Log.w(TAG, "Multiple volumes not currently supported"); 2237fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat return; 2247fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 225b104340496e3a531e26c8f428c808eca0e039f50San Mehat 226b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (mLegacyState.equals(state)) { 227b104340496e3a531e26c8f428c808eca0e039f50San Mehat Log.w(TAG, String.format("Duplicate state transition (%s -> %s)", mLegacyState, state)); 228b104340496e3a531e26c8f428c808eca0e039f50San Mehat return; 229b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 2307fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 2314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String oldState = mLegacyState; 2324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mLegacyState = state; 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 2354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for (int i = mListeners.size() -1; i >= 0; i--) { 2364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = mListeners.get(i); 2374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 238b104340496e3a531e26c8f428c808eca0e039f50San Mehat bl.mListener.onStorageStateChanged(path, oldState, state); 2394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 2404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.e(TAG, "Listener dead"); 2414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(i); 2424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 2434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.e(TAG, "Listener failed", ex); 2444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat /** 25022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * 25122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * Callback from NativeDaemonConnector 25222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat */ 25322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public void onDaemonConnected() { 2545b77dab23469273d41f9c530d947ac055765e6eaSan Mehat /* 2555b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * Since we'll be calling back into the NativeDaemonConnector, 2565b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * we need to do our work in a new thread. 2575b77dab23469273d41f9c530d947ac055765e6eaSan Mehat */ 2587fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat new Thread() { 2597fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat public void run() { 2605b77dab23469273d41f9c530d947ac055765e6eaSan Mehat /** 2615b77dab23469273d41f9c530d947ac055765e6eaSan Mehat * Determine media state and UMS detection status 2625b77dab23469273d41f9c530d947ac055765e6eaSan Mehat */ 2635b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String path = Environment.getExternalStorageDirectory().getPath(); 2645b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String state = Environment.MEDIA_REMOVED; 2655b77dab23469273d41f9c530d947ac055765e6eaSan Mehat 2667fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat try { 2675b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String[] vols = mConnector.doListCommand( 2684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat "volume list", VoldResponseCode.VolumeListResult); 2695b77dab23469273d41f9c530d947ac055765e6eaSan Mehat for (String volstr : vols) { 2705b77dab23469273d41f9c530d947ac055765e6eaSan Mehat String[] tok = volstr.split(" "); 2715b77dab23469273d41f9c530d947ac055765e6eaSan Mehat // FMT: <label> <mountpoint> <state> 2725b77dab23469273d41f9c530d947ac055765e6eaSan Mehat if (!tok[1].equals(path)) { 2735b77dab23469273d41f9c530d947ac055765e6eaSan Mehat Log.w(TAG, String.format( 2745b77dab23469273d41f9c530d947ac055765e6eaSan Mehat "Skipping unknown volume '%s'",tok[1])); 2755b77dab23469273d41f9c530d947ac055765e6eaSan Mehat continue; 2765b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } 2775b77dab23469273d41f9c530d947ac055765e6eaSan Mehat int st = Integer.parseInt(tok[2]); 2785b77dab23469273d41f9c530d947ac055765e6eaSan Mehat if (st == VolumeState.NoMedia) { 2795b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_REMOVED; 2805b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Idle) { 281207e538350665cea00e1aa70b8094beca4a34e45San Mehat state = Environment.MEDIA_UNMOUNTED; 2825b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Mounted) { 2835b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_MOUNTED; 2845b77dab23469273d41f9c530d947ac055765e6eaSan Mehat Log.i(TAG, "Media already mounted on daemon connection"); 2855b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else if (st == VolumeState.Shared) { 2865b77dab23469273d41f9c530d947ac055765e6eaSan Mehat state = Environment.MEDIA_SHARED; 2875b77dab23469273d41f9c530d947ac055765e6eaSan Mehat Log.i(TAG, "Media shared on daemon connection"); 2885b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } else { 2895b77dab23469273d41f9c530d947ac055765e6eaSan Mehat throw new Exception(String.format("Unexpected state %d", st)); 2907fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 2917fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 292c2a39471642e31d7350910612e40d078b825173aSan Mehat if (state != null) { 293c2a39471642e31d7350910612e40d078b825173aSan Mehat updatePublicVolumeState(path, state); 294c2a39471642e31d7350910612e40d078b825173aSan Mehat } 2955b77dab23469273d41f9c530d947ac055765e6eaSan Mehat } catch (Exception e) { 2965b77dab23469273d41f9c530d947ac055765e6eaSan Mehat Log.e(TAG, "Error processing initial volume state", e); 2975b77dab23469273d41f9c530d947ac055765e6eaSan Mehat updatePublicVolumeState(path, Environment.MEDIA_REMOVED); 2987fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 2997fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 3007fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat try { 301207e538350665cea00e1aa70b8094beca4a34e45San Mehat boolean avail = doGetShareMethodAvailable("ums"); 3027fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat notifyShareAvailabilityChange("ums", avail); 3037fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } catch (Exception ex) { 3047fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat Log.w(TAG, "Failed to get share availability"); 3057fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 306207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 307207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Now that we've done our initialization, release 308207e538350665cea00e1aa70b8094beca4a34e45San Mehat * the hounds! 309207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 310207e538350665cea00e1aa70b8094beca4a34e45San Mehat mReady = true; 3117fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 3127fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat }.start(); 3137fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 3147fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 31522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat /** 31622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat * Callback from NativeDaemonConnector 31722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat */ 31822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat public boolean onEvent(int code, String raw, String[] cooked) { 3194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Intent in = null; 3204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 32122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat if (code == VoldResponseCode.VolumeStateChange) { 3224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 3234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * One of the volumes we're managing has changed state. 3244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Format: "NNN Volume <label> <path> state changed 3254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * from <old_#> (<old_str>) to <new_#> (<new_str>)" 3264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 32722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat notifyVolumeStateChange( 32822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat cooked[2], cooked[3], Integer.parseInt(cooked[7]), 32922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat Integer.parseInt(cooked[10])); 33022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else if (code == VoldResponseCode.ShareAvailabilityChange) { 33122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Share method <method> now <available|unavailable> 33222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat boolean avail = false; 33322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat if (cooked[5].equals("available")) { 33422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat avail = true; 33522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 33622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat notifyShareAvailabilityChange(cooked[3], avail); 3374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if ((code == VoldResponseCode.VolumeDiskInserted) || 3384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat (code == VoldResponseCode.VolumeDiskRemoved) || 3394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat (code == VoldResponseCode.VolumeBadRemoval)) { 34022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>) 34122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>) 34222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>) 3434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final String label = cooked[2]; 3444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat final String path = cooked[3]; 3454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int major = -1; 3464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int minor = -1; 3474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 3484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 3494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String devComp = cooked[6].substring(1, cooked[6].length() -1); 3504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String[] devTok = devComp.split(":"); 3514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat major = Integer.parseInt(devTok[0]); 3524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat minor = Integer.parseInt(devTok[1]); 3534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 3544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.e(TAG, "Failed to parse major/minor", ex); 3554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 3564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 3574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (code == VoldResponseCode.VolumeDiskInserted) { 3584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat new Thread() { 3594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void run() { 3604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 3614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int rc; 362b104340496e3a531e26c8f428c808eca0e039f50San Mehat if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) { 3634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.w(TAG, String.format("Insertion mount failed (%d)", rc)); 3644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 3654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (Exception ex) { 3664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.w(TAG, "Failed to mount media on insertion", ex); 3674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 3684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 3694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat }.start(); 3704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (code == VoldResponseCode.VolumeDiskRemoved) { 3714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 3724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * This event gets trumped if we're already in BAD_REMOVAL state 3734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 3744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) { 3754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return true; 3764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 3774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 3784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 3794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); 3804270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 3814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 3824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_REMOVED); 3834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_REMOVED, Uri.parse("file://" + path)); 3844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (code == VoldResponseCode.VolumeBadRemoval) { 3854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 3864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 3874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); 3884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 3894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 3904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL); 3914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL, Uri.parse("file://" + path)); 3924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else { 3934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.e(TAG, String.format("Unknown code {%d}", code)); 3944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 39522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else { 39622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat return false; 39722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 3984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 3994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (in != null) { 4004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 4014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 40222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat return true; 40322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 40422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat 405207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void notifyVolumeStateChange(String label, String path, int oldState, int newState) { 4064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String vs = getVolumeState(path); 4074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 4084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Intent in = null; 4097fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 4107fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat if (newState == VolumeState.Init) { 4117fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.NoMedia) { 4127fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat // NoMedia is handled via Disk Remove events 4137fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Idle) { 4145fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat /* 4155fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or 4165fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat * if we're in the process of enabling UMS 4175fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat */ 4184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!vs.equals( 4194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Environment.MEDIA_BAD_REMOVAL) && !vs.equals( 4204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Environment.MEDIA_NOFS) && !vs.equals( 4214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Environment.MEDIA_UNMOUNTABLE) && !mUmsEnabling) { 4224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 4234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); 4247fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 4257fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Pending) { 4267fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Checking) { 4274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_CHECKING); 4284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_CHECKING, Uri.parse("file://" + path)); 4297fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Mounted) { 4304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_MOUNTED); 4314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat // Update media status on PackageManagerService to mount packages on sdcard 4324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mPms.updateExternalMediaStatus(true); 4334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + path)); 4344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in.putExtra("read-only", false); 4357fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Unmounting) { 4364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mPms.updateExternalMediaStatus(false); 4374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_EJECT, Uri.parse("file://" + path)); 4387fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Formatting) { 4397fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.Shared) { 4404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* Send the media unmounted event first */ 4414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED); 4424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path)); 4434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 4444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 4454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat updatePublicVolumeState(path, Environment.MEDIA_SHARED); 4464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat in = new Intent(Intent.ACTION_MEDIA_SHARED, Uri.parse("file://" + path)); 4477fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else if (newState == VolumeState.SharedMnt) { 4484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.e(TAG, "Live shared mounts not supported yet!"); 4494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return; 4507fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } else { 4517fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat Log.e(TAG, "Unhandled VolumeState {" + newState + "}"); 4527fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 4537fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 4544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (in != null) { 4554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mContext.sendBroadcast(in); 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 459207e538350665cea00e1aa70b8094beca4a34e45San Mehat private boolean doGetShareMethodAvailable(String method) { 460207e538350665cea00e1aa70b8094beca4a34e45San Mehat ArrayList<String> rsp = mConnector.doCommand("share status " + method); 461207e538350665cea00e1aa70b8094beca4a34e45San Mehat 462207e538350665cea00e1aa70b8094beca4a34e45San Mehat for (String line : rsp) { 463207e538350665cea00e1aa70b8094beca4a34e45San Mehat String []tok = line.split(" "); 464207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code; 465207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 466207e538350665cea00e1aa70b8094beca4a34e45San Mehat code = Integer.parseInt(tok[0]); 467207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NumberFormatException nfe) { 468207e538350665cea00e1aa70b8094beca4a34e45San Mehat Log.e(TAG, String.format("Error parsing code %s", tok[0])); 469207e538350665cea00e1aa70b8094beca4a34e45San Mehat return false; 470207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 471207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.ShareStatusResult) { 472207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (tok[2].equals("available")) 473207e538350665cea00e1aa70b8094beca4a34e45San Mehat return true; 474207e538350665cea00e1aa70b8094beca4a34e45San Mehat return false; 475207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 476207e538350665cea00e1aa70b8094beca4a34e45San Mehat Log.e(TAG, String.format("Unexpected response code %d", code)); 477207e538350665cea00e1aa70b8094beca4a34e45San Mehat return false; 478207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 479207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 480207e538350665cea00e1aa70b8094beca4a34e45San Mehat Log.e(TAG, "Got an empty response"); 481207e538350665cea00e1aa70b8094beca4a34e45San Mehat return false; 482207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 483207e538350665cea00e1aa70b8094beca4a34e45San Mehat 484207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doMountVolume(String path) { 485b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 486207e538350665cea00e1aa70b8094beca4a34e45San Mehat 487207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 488207e538350665cea00e1aa70b8094beca4a34e45San Mehat mConnector.doCommand(String.format("volume mount %s", path)); 489207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 490207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 491207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Mount failed for some reason 492207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 493207e538350665cea00e1aa70b8094beca4a34e45San Mehat Intent in = null; 494207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 495207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedNoMedia) { 496207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 497207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Attempt to mount but no media inserted 498207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 499b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedNoMedia; 500207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaBlank) { 501207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 502207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Media is blank or does not contain a supported filesystem 503207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 504207e538350665cea00e1aa70b8094beca4a34e45San Mehat updatePublicVolumeState(path, Environment.MEDIA_NOFS); 505207e538350665cea00e1aa70b8094beca4a34e45San Mehat in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path)); 506b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedMediaBlank; 507207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { 508207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 509207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Volume consistency check failed 510207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 511207e538350665cea00e1aa70b8094beca4a34e45San Mehat updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE); 512207e538350665cea00e1aa70b8094beca4a34e45San Mehat in = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path)); 513b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedMediaCorrupt; 514207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 515b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 516207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 517207e538350665cea00e1aa70b8094beca4a34e45San Mehat 518207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 519207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Send broadcast intent (if required for the failure) 520207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 521207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (in != null) { 522207e538350665cea00e1aa70b8094beca4a34e45San Mehat mContext.sendBroadcast(in); 523207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 524207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 525207e538350665cea00e1aa70b8094beca4a34e45San Mehat 526207e538350665cea00e1aa70b8094beca4a34e45San Mehat return rc; 527207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 528207e538350665cea00e1aa70b8094beca4a34e45San Mehat 529207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doUnmountVolume(String path) { 53059443a673a736978361dc341f41ce4e9dae053a0San Mehat if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) { 531207e538350665cea00e1aa70b8094beca4a34e45San Mehat return VoldResponseCode.OpFailedVolNotMounted; 532207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 533207e538350665cea00e1aa70b8094beca4a34e45San Mehat 534207e538350665cea00e1aa70b8094beca4a34e45San Mehat // Notify PackageManager of potential media removal and deal with 535207e538350665cea00e1aa70b8094beca4a34e45San Mehat // return code later on. The caller of this api should be aware or have been 536207e538350665cea00e1aa70b8094beca4a34e45San Mehat // notified that the applications installed on the media will be killed. 537207e538350665cea00e1aa70b8094beca4a34e45San Mehat mPms.updateExternalMediaStatus(false); 538207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 539207e538350665cea00e1aa70b8094beca4a34e45San Mehat mConnector.doCommand(String.format("volume unmount %s", path)); 540b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationSucceeded; 541207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 542207e538350665cea00e1aa70b8094beca4a34e45San Mehat // Don't worry about mismatch in PackageManager since the 543207e538350665cea00e1aa70b8094beca4a34e45San Mehat // call back will handle the status changes any way. 544207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 545207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedVolNotMounted) { 546a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageNotMounted; 547207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 548b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedInternalError; 549207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 550207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 551207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 552207e538350665cea00e1aa70b8094beca4a34e45San Mehat 553207e538350665cea00e1aa70b8094beca4a34e45San Mehat private int doFormatVolume(String path) { 554207e538350665cea00e1aa70b8094beca4a34e45San Mehat try { 555207e538350665cea00e1aa70b8094beca4a34e45San Mehat String cmd = String.format("volume format %s", path); 556207e538350665cea00e1aa70b8094beca4a34e45San Mehat mConnector.doCommand(cmd); 557b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationSucceeded; 558207e538350665cea00e1aa70b8094beca4a34e45San Mehat } catch (NativeDaemonConnectorException e) { 559207e538350665cea00e1aa70b8094beca4a34e45San Mehat int code = e.getCode(); 560207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (code == VoldResponseCode.OpFailedNoMedia) { 561b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedNoMedia; 562207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else if (code == VoldResponseCode.OpFailedMediaCorrupt) { 563b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedMediaCorrupt; 564207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 565b104340496e3a531e26c8f428c808eca0e039f50San Mehat return StorageResultCode.OperationFailedInternalError; 566207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 567207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 568207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 569207e538350665cea00e1aa70b8094beca4a34e45San Mehat 570b104340496e3a531e26c8f428c808eca0e039f50San Mehat private boolean doGetVolumeShared(String path, String method) { 571b104340496e3a531e26c8f428c808eca0e039f50San Mehat String cmd = String.format("volume shared %s %s", path, method); 572b104340496e3a531e26c8f428c808eca0e039f50San Mehat ArrayList<String> rsp = mConnector.doCommand(cmd); 573b104340496e3a531e26c8f428c808eca0e039f50San Mehat 574b104340496e3a531e26c8f428c808eca0e039f50San Mehat for (String line : rsp) { 575b104340496e3a531e26c8f428c808eca0e039f50San Mehat String []tok = line.split(" "); 576b104340496e3a531e26c8f428c808eca0e039f50San Mehat int code; 577b104340496e3a531e26c8f428c808eca0e039f50San Mehat try { 578b104340496e3a531e26c8f428c808eca0e039f50San Mehat code = Integer.parseInt(tok[0]); 579b104340496e3a531e26c8f428c808eca0e039f50San Mehat } catch (NumberFormatException nfe) { 580b104340496e3a531e26c8f428c808eca0e039f50San Mehat Log.e(TAG, String.format("Error parsing code %s", tok[0])); 581b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 582b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 583b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (code == VoldResponseCode.ShareEnabledResult) { 584b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (tok[2].equals("enabled")) 585b104340496e3a531e26c8f428c808eca0e039f50San Mehat return true; 586b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 587b104340496e3a531e26c8f428c808eca0e039f50San Mehat } else { 588b104340496e3a531e26c8f428c808eca0e039f50San Mehat Log.e(TAG, String.format("Unexpected response code %d", code)); 589b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 590b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 591b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 592b104340496e3a531e26c8f428c808eca0e039f50San Mehat Log.e(TAG, "Got an empty response"); 593b104340496e3a531e26c8f428c808eca0e039f50San Mehat return false; 594b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 595b104340496e3a531e26c8f428c808eca0e039f50San Mehat 596207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void notifyShareAvailabilityChange(String method, final boolean avail) { 5977fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat if (!method.equals("ums")) { 5987fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat Log.w(TAG, "Ignoring unsupported share method {" + method + "}"); 5997fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat return; 6007fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6011f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat 6024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 6034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for (int i = mListeners.size() -1; i >= 0; i--) { 6044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = mListeners.get(i); 6051f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat try { 606b104340496e3a531e26c8f428c808eca0e039f50San Mehat bl.mListener.onUsbMassStorageConnectionChanged(avail); 6074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 6084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.e(TAG, "Listener dead"); 6094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(i); 6101f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } catch (Exception ex) { 6114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.e(TAG, "Listener failed", ex); 6121f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 6131f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 6144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6157fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 616207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (mBooted == true) { 617207e538350665cea00e1aa70b8094beca4a34e45San Mehat Intent intent; 618207e538350665cea00e1aa70b8094beca4a34e45San Mehat if (avail) { 619207e538350665cea00e1aa70b8094beca4a34e45San Mehat intent = new Intent(Intent.ACTION_UMS_CONNECTED); 620207e538350665cea00e1aa70b8094beca4a34e45San Mehat } else { 621207e538350665cea00e1aa70b8094beca4a34e45San Mehat intent = new Intent(Intent.ACTION_UMS_DISCONNECTED); 622207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 623207e538350665cea00e1aa70b8094beca4a34e45San Mehat mContext.sendBroadcast(intent); 6241f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 627207e538350665cea00e1aa70b8094beca4a34e45San Mehat private void validatePermission(String perm) { 6284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) { 6294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new SecurityException(String.format("Requires %s permission", perm)); 6304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6317fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6327fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 634207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Constructs a new MountService instance 635207e538350665cea00e1aa70b8094beca4a34e45San Mehat * 636207e538350665cea00e1aa70b8094beca4a34e45San Mehat * @param context Binder context for this service 637207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 638207e538350665cea00e1aa70b8094beca4a34e45San Mehat public MountService(Context context) { 639207e538350665cea00e1aa70b8094beca4a34e45San Mehat mContext = context; 640207e538350665cea00e1aa70b8094beca4a34e45San Mehat 641207e538350665cea00e1aa70b8094beca4a34e45San Mehat /* 642207e538350665cea00e1aa70b8094beca4a34e45San Mehat * Vold does not run in the simulator, so fake out a mounted 643207e538350665cea00e1aa70b8094beca4a34e45San Mehat * event to trigger MediaScanner 644207e538350665cea00e1aa70b8094beca4a34e45San Mehat */ 645207e538350665cea00e1aa70b8094beca4a34e45San Mehat if ("simulator".equals(SystemProperties.get("ro.product.device"))) { 646207e538350665cea00e1aa70b8094beca4a34e45San Mehat updatePublicVolumeState("/sdcard", Environment.MEDIA_MOUNTED); 647207e538350665cea00e1aa70b8094beca4a34e45San Mehat return; 648207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 649207e538350665cea00e1aa70b8094beca4a34e45San Mehat 650207e538350665cea00e1aa70b8094beca4a34e45San Mehat // XXX: This will go away soon in favor of IMountServiceObserver 651207e538350665cea00e1aa70b8094beca4a34e45San Mehat mPms = (PackageManagerService) ServiceManager.getService("package"); 652207e538350665cea00e1aa70b8094beca4a34e45San Mehat 653207e538350665cea00e1aa70b8094beca4a34e45San Mehat mContext.registerReceiver(mBroadcastReceiver, 654207e538350665cea00e1aa70b8094beca4a34e45San Mehat new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null); 655207e538350665cea00e1aa70b8094beca4a34e45San Mehat 656207e538350665cea00e1aa70b8094beca4a34e45San Mehat mListeners = new ArrayList<MountServiceBinderListener>(); 657207e538350665cea00e1aa70b8094beca4a34e45San Mehat 658207e538350665cea00e1aa70b8094beca4a34e45San Mehat mConnector = new NativeDaemonConnector(this, "vold", 10, "VoldConnector"); 659207e538350665cea00e1aa70b8094beca4a34e45San Mehat mReady = false; 660207e538350665cea00e1aa70b8094beca4a34e45San Mehat Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName()); 661207e538350665cea00e1aa70b8094beca4a34e45San Mehat thread.start(); 662207e538350665cea00e1aa70b8094beca4a34e45San Mehat } 663207e538350665cea00e1aa70b8094beca4a34e45San Mehat 664207e538350665cea00e1aa70b8094beca4a34e45San Mehat /** 6654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * Exposed API calls below here 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6677fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 6684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void registerListener(IMountServiceListener listener) { 6694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 6704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat MountServiceBinderListener bl = new MountServiceBinderListener(listener); 6714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 6724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat listener.asBinder().linkToDeath(bl, 0); 6734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.add(bl); 6744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (RemoteException rex) { 6754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.e(TAG, "Failed to link to listener death"); 6764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6777fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6804270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void unregisterListener(IMountServiceListener listener) { 6814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat synchronized (mListeners) { 6824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat for(MountServiceBinderListener bl : mListeners) { 6834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (bl.mListener == listener) { 6844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mListeners.remove(mListeners.indexOf(bl)); 6854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return; 6864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public void shutdown() { 6924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.SHUTDOWN); 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.i(TAG, "Shutting down"); 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String path = Environment.getExternalStorageDirectory().getPath(); 6974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String state = getVolumeState(path); 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (state.equals(Environment.MEDIA_SHARED)) { 7004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 7014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * If the media is currently shared, unshare it. 7024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * XXX: This is still dangerous!. We should not 7034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * be rebooting at *all* if UMS is enabled, since 7044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * the UMS host could have dirty FAT cache entries 7054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * yet to flush. 7064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 707b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (setUsbMassStorageEnabled(false) != StorageResultCode.OperationSucceeded) { 7084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.e(TAG, "UMS disable on shutdown failed"); 7094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } else if (state.equals(Environment.MEDIA_CHECKING)) { 7114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 7124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * If the media is being checked, then we need to wait for 7134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * it to complete before being able to proceed. 7144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 7154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat // XXX: @hackbod - Should we disable the ANR timer here? 7164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat int retries = 30; 7174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) { 7184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 7194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Thread.sleep(1000); 7204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (InterruptedException iex) { 7214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.e(TAG, "Interrupted while waiting for media", iex); 7224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat break; 7234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat state = Environment.getExternalStorageState(); 7254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (retries == 0) { 7274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.e(TAG, "Timed out waiting for media to check"); 7284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7297fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat } 7307fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 7314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (state.equals(Environment.MEDIA_MOUNTED)) { 7324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 7334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * If the media is mounted, then gracefully unmount it. 7344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 735b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (doUnmountVolume(path) != StorageResultCode.OperationSucceeded) { 7364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.e(TAG, "Failed to unmount media for shutdown"); 7374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7381f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat } 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 741b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageConnected() { 742207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 7437fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat 744b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (mUmsEnabling) { 745b104340496e3a531e26c8f428c808eca0e039f50San Mehat return true; 746b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 747b104340496e3a531e26c8f428c808eca0e039f50San Mehat return doGetShareMethodAvailable("ums"); 7484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 750b104340496e3a531e26c8f428c808eca0e039f50San Mehat public int setUsbMassStorageEnabled(boolean enable) { 751207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 752b104340496e3a531e26c8f428c808eca0e039f50San Mehat 753b104340496e3a531e26c8f428c808eca0e039f50San Mehat return doShareUnshareVolume(Environment.getExternalStorageDirectory().getPath(), "ums", enable); 7544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 756b104340496e3a531e26c8f428c808eca0e039f50San Mehat public boolean isUsbMassStorageEnabled() { 757207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 758b104340496e3a531e26c8f428c808eca0e039f50San Mehat return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums"); 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * @return state of the volume at the specified mount point 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String getVolumeState(String mountPoint) { 7654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat /* 7664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * XXX: Until we have multiple volume discovery, just hardwire 7674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat * this to /sdcard 7684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat */ 7694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat if (!mountPoint.equals(Environment.getExternalStorageDirectory().getPath())) { 7704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume"); 7714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat throw new IllegalArgumentException(); 7724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 7744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return mLegacyState; 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 7774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int mountVolume(String path) { 7784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 780207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 781207e538350665cea00e1aa70b8094beca4a34e45San Mehat return doMountVolume(path); 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int unmountVolume(String path) { 7854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); 786207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 788207e538350665cea00e1aa70b8094beca4a34e45San Mehat return doUnmountVolume(path); 7894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int formatVolume(String path) { 7924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS); 793207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 795207e538350665cea00e1aa70b8094beca4a34e45San Mehat return doFormatVolume(path); 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7973697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 798b104340496e3a531e26c8f428c808eca0e039f50San Mehat private void warnOnNotMounted() { 799b104340496e3a531e26c8f428c808eca0e039f50San Mehat if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 800b104340496e3a531e26c8f428c808eca0e039f50San Mehat Log.w(TAG, "getSecureContainerList() called when storage not mounted"); 801b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 802b104340496e3a531e26c8f428c808eca0e039f50San Mehat } 803b104340496e3a531e26c8f428c808eca0e039f50San Mehat 8044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String[] getSecureContainerList() { 8054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 806207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 807b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 808f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 8094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 8104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult); 8114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 8124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return new String[0]; 81302735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 8143697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 8153697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 8164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int createSecureContainer(String id, int sizeMb, String fstype, 8174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String key, int ownerUid) { 8184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_CREATE); 819207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 820b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 8214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 822b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 8234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String cmd = String.format("asec create %s %d %s %s %d", id, sizeMb, fstype, key, ownerUid); 8244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 8254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 8264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 827b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 82802735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 829a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 830a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (rc == StorageResultCode.OperationSucceeded) { 831a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 832a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat mAsecMountSet.add(id); 833a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 834a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 8354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 8363697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 8373697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 8384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int finalizeSecureContainer(String id) { 8394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_CREATE); 840b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 8414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 842b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 8434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 8444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(String.format("asec finalize %s", id)); 845a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat /* 846a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat * Finalization does a remount, so no need 847a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat * to update mAsecMountSet 848a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat */ 8494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 850b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 85102735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 8524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 8533697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 8543697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 8554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int destroySecureContainer(String id) { 8564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_DESTROY); 857207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 858b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 859f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 860b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 8614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 8624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(String.format("asec destroy %s", id)); 8634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 864b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 86502735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 866a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 867a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (rc == StorageResultCode.OperationSucceeded) { 868a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 869a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (mAsecMountSet.contains(id)) { 870a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat mAsecMountSet.remove(id); 871a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 872a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 873a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 874a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 8754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 8763697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 8773697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 8784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int mountSecureContainer(String id, String key, int ownerUid) { 8794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 880207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 881b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 8824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 883a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 884a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (mAsecMountSet.contains(id)) { 885a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageMounted; 886a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 887a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 888a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 889b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 8904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String cmd = String.format("asec mount %s %s %d", id, key, ownerUid); 8914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 8924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 8934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 894b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 89502735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 8966cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 8976cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (rc == StorageResultCode.OperationSucceeded) { 8986cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 8996cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat mAsecMountSet.add(id); 9006cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 9016cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 9024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 9033697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat } 9043697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 9054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int unmountSecureContainer(String id) { 9064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT); 907207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 908b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 9094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 9106cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 9116cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (!mAsecMountSet.contains(id)) { 912a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageNotMounted; 9136cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 9146cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 9156cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 916b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 9174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String cmd = String.format("asec unmount %s", id); 9184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 9194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 9204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 921b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 92202735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 9236cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 9246cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat if (rc == StorageResultCode.OperationSucceeded) { 9256cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 9266cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat mAsecMountSet.remove(id); 9276cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 9286cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 9294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 9309dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat } 9319dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat 9326cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat public boolean isSecureContainerMounted(String id) { 9336cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 9346cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat waitForReady(); 9356cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat warnOnNotMounted(); 9366cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 9376cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat synchronized (mAsecMountSet) { 9386cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat return mAsecMountSet.contains(id); 9396cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 9406cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat } 9416cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat 9424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public int renameSecureContainer(String oldId, String newId) { 9434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_RENAME); 944207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 945b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 9464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 947a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat synchronized (mAsecMountSet) { 948a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat if (mAsecMountSet.contains(oldId)) { 949a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat return StorageResultCode.OperationFailedStorageMounted; 950a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 951a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat } 952a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 953b104340496e3a531e26c8f428c808eca0e039f50San Mehat int rc = StorageResultCode.OperationSucceeded; 9544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat String cmd = String.format("asec rename %s %s", oldId, newId); 9554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat try { 9564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat mConnector.doCommand(cmd); 9574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat } catch (NativeDaemonConnectorException e) { 958b104340496e3a531e26c8f428c808eca0e039f50San Mehat rc = StorageResultCode.OperationFailedInternalError; 95902735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat } 960a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat 9614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return rc; 96245f61040823d8c442838f75cde8760f236603daeSan Mehat } 96345f61040823d8c442838f75cde8760f236603daeSan Mehat 9644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat public String getSecureContainerPath(String id) { 9654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat validatePermission(android.Manifest.permission.ASEC_ACCESS); 966207e538350665cea00e1aa70b8094beca4a34e45San Mehat waitForReady(); 967b104340496e3a531e26c8f428c808eca0e039f50San Mehat warnOnNotMounted(); 968f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat 9694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat ArrayList<String> rsp = mConnector.doCommand("asec path " + id); 9703697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat 97122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat for (String line : rsp) { 97222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat String []tok = line.split(" "); 97322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat int code = Integer.parseInt(tok[0]); 97422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat if (code == VoldResponseCode.AsecPathResult) { 97522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat return tok[1]; 97622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } else { 9774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.e(TAG, String.format("Unexpected response code %d", code)); 9784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return ""; 97922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 98022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 9814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat 9824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat Log.e(TAG, "Got an empty response"); 9834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat return ""; 98422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat } 9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 987