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