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