MountService.java revision 5ac72a29593ab9a20337a2225df52bdf4754be02
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.server;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport com.android.internal.app.IMediaContainerService;
202f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport com.android.internal.util.XmlUtils;
21c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport com.android.server.am.ActivityManagerService;
22cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Rootimport com.android.server.pm.PackageManagerService;
23dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkeyimport com.android.server.NativeDaemonConnector.Command;
24c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
258888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parksimport android.Manifest;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
27a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ComponentName;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
31a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ServiceConnection;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
3302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.content.res.ObbInfo;
342f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.Resources;
352f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.TypedArray;
362f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.XmlResourceParser;
37ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwoodimport android.hardware.usb.UsbManager;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri;
3902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.os.Binder;
40a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.Environment;
41c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Handler;
425f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.HandlerThread;
43a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.IBinder;
445f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.Looper;
45c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Message;
462f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.os.Parcelable;
474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehatimport android.os.RemoteException;
48fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapuimport android.os.ServiceManager;
49207e538350665cea00e1aa70b8094beca4a34e45San Mehatimport android.os.SystemClock;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties;
51f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport android.os.UserHandle;
52a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountService;
53a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountServiceListener;
54a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountShutdownObserver;
55a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IObbActionListener;
56af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Rootimport android.os.storage.OnObbStateChangeListener;
57a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.StorageResultCode;
582f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.os.storage.StorageVolume;
59f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parksimport android.text.TextUtils;
602f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.util.AttributeSet;
61a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehatimport android.util.Slog;
622f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.util.Xml;
632f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
642f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport org.xmlpull.v1.XmlPullParser;
652f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport org.xmlpull.v1.XmlPullParserException;
66a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
6738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.FileDescriptor;
6805105f7abe02b2dff91d6260b3628c8b97816babKenny Rootimport java.io.IOException;
6938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.PrintWriter;
703b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.math.BigInteger;
71735de3b38abbd6564082a819377673ee593744a6Kenny Rootimport java.security.NoSuchAlgorithmException;
723b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.InvalidKeySpecException;
733b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.KeySpec;
7422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehatimport java.util.ArrayList;
75a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.HashMap;
766cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehatimport java.util.HashSet;
7738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Iterator;
78a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.LinkedList;
79a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.List;
80a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.Map;
8138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Map.Entry;
8251a573c76737733638c475f52e441c814e6645ccKenny Rootimport java.util.concurrent.CountDownLatch;
8351a573c76737733638c475f52e441c814e6645ccKenny Rootimport java.util.concurrent.TimeUnit;
848fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwoodimport java.util.Set;
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
863b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKey;
873b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKeyFactory;
883b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.spec.PBEKeySpec;
893b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
91b104340496e3a531e26c8f428c808eca0e039f50San Mehat * MountService implements back-end services for platform storage
92b104340496e3a531e26c8f428c808eca0e039f50San Mehat * management.
93b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @hide - Applications should use android.os.storage.StorageManager
94b104340496e3a531e26c8f428c808eca0e039f50San Mehat * to access the MountService.
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
96fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkeyclass MountService extends IMountService.Stub
97fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey        implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
985af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
99b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private static final boolean LOCAL_LOGD = false;
1008a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu    private static final boolean DEBUG_UNMOUNT = false;
1018a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu    private static final boolean DEBUG_EVENTS = false;
102b7db2726e91f1d9480359d0f83b9cb7769906b34Kenny Root    private static final boolean DEBUG_OBB = false;
10302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
10407714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root    // Disable this since it messes up long-running cryptfs operations.
10507714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root    private static final boolean WATCHDOG_ENABLE = false;
10607714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "MountService";
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
109305bcbf0c961840c4505770d084a1caacc074dbbKenny Root    private static final String VOLD_TAG = "VoldConnector";
110305bcbf0c961840c4505770d084a1caacc074dbbKenny Root
111cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root    /** Maximum number of ASEC containers allowed to be mounted. */
112cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root    private static final int MAX_CONTAINERS = 250;
113cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root
1144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    /*
1154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Internal vold volume state constants
1164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     */
1177fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    class VolumeState {
1187fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Init       = -1;
1197fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int NoMedia    = 0;
1207fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Idle       = 1;
1217fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Pending    = 2;
1227fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Checking   = 3;
1237fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Mounted    = 4;
1247fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Unmounting = 5;
1257fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Formatting = 6;
1267fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Shared     = 7;
1277fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int SharedMnt  = 8;
1287fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
1297fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
1304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    /*
1314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Internal vold response code constants
1324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     */
13322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    class VoldResponseCode {
1344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 100 series - Requestion action was initiated; expect another reply
1364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         *              before proceeding with a new command.
1374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
13822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeListResult               = 110;
13922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int AsecListResult                 = 111;
140c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        public static final int StorageUsersListResult         = 112;
14122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
1424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 200 series - Requestion action has been successfully completed.
1444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
1454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int ShareStatusResult              = 210;
14622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int AsecPathResult                 = 211;
1474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int ShareEnabledResult             = 212;
14822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
1494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 400 series - Command was accepted, but the requested action
1514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         *              did not take place.
1524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
1534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedNoMedia                = 401;
1544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedMediaBlank             = 402;
1554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedMediaCorrupt           = 403;
1564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedVolNotMounted          = 404;
157d970998b0d489774ad1c5b94b47d233912f00214San Mehat        public static final int OpFailedStorageBusy            = 405;
1582d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        public static final int OpFailedStorageNotFound        = 406;
1594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 600 series - Unsolicited broadcasts.
1624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
16322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeStateChange              = 605;
16422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeDiskInserted             = 630;
16522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeDiskRemoved              = 631;
16622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeBadRemoval               = 632;
16722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
16822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
1694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private Context                               mContext;
1704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private NativeDaemonConnector                 mConnector;
1712f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    private final ArrayList<StorageVolume>        mVolumes = new ArrayList<StorageVolume>();
1722f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    private StorageVolume                         mPrimaryVolume;
1737fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood    private final HashMap<String, String>         mVolumeStates = new HashMap<String, String>();
174a5250c93928e256738125b265e10c96c3575597eMike Lockwood    private final HashMap<String, StorageVolume>  mVolumeMap = new HashMap<String, StorageVolume>();
1757fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood    private String                                mExternalStoragePath;
1764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private PackageManagerService                 mPms;
1774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private boolean                               mUmsEnabling;
178ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood    private boolean                               mUmsAvailable = false;
1790eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    // Used as a lock for methods that register/unregister listeners.
1800eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    final private ArrayList<MountServiceBinderListener> mListeners =
1810eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            new ArrayList<MountServiceBinderListener>();
1826a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private boolean                               mBooted = false;
18351a573c76737733638c475f52e441c814e6645ccKenny Root    private CountDownLatch                        mConnectedSignal = new CountDownLatch(1);
18451a573c76737733638c475f52e441c814e6645ccKenny Root    private CountDownLatch                        mAsecsScanned = new CountDownLatch(1);
1856a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private boolean                               mSendUmsConnectedOnBoot = false;
18603559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood    // true if we should fake MEDIA_MOUNTED state for external storage
18703559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood    private boolean                               mEmulateExternalStorage = false;
188fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapu
1896cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    /**
1906cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat     * Private hash of currently mounted secure containers.
1910eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu     * Used as a lock in methods to manipulate secure containers.
1926cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat     */
1930eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    final private HashSet<String> mAsecMountSet = new HashSet<String>();
1946cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
19502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    /**
1963b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * The size of the crypto algorithm key in bits for OBB files. Currently
1973b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * Twofish is used which takes 128-bit keys.
1983b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     */
1993b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
2003b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
2013b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    /**
2023b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * The number of times to run SHA1 in the PBKDF2 function for OBB files.
2033b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * 1024 is reasonably secure and not too slow.
2043b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     */
2053b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    private static final int PBKDF2_HASH_ROUNDS = 1024;
2063b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
2073b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    /**
208a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * Mounted OBB tracking information. Used to track the current state of all
209a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * OBBs.
210a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     */
211735de3b38abbd6564082a819377673ee593744a6Kenny Root    final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
212a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
213a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
214a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class ObbState implements IBinder.DeathRecipient {
215af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        public ObbState(String filename, int callerUid, IObbActionListener token, int nonce)
216735de3b38abbd6564082a819377673ee593744a6Kenny Root                throws RemoteException {
217a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            this.filename = filename;
218a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            this.callerUid = callerUid;
219af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            this.token = token;
220af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            this.nonce = nonce;
221a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
222a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
223a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        // OBB source filename
224af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        String filename;
225a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
226a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        // Binder.callingUid()
22705105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final public int callerUid;
228a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
229af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        // Token of remote Binder caller
230af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IObbActionListener token;
231af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
232af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        // Identifier to pass back to the token
233af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final int nonce;
234a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
235735de3b38abbd6564082a819377673ee593744a6Kenny Root        public IBinder getBinder() {
236735de3b38abbd6564082a819377673ee593744a6Kenny Root            return token.asBinder();
237735de3b38abbd6564082a819377673ee593744a6Kenny Root        }
238735de3b38abbd6564082a819377673ee593744a6Kenny Root
239a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
240a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void binderDied() {
241a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            ObbAction action = new UnmountObbAction(this, true);
242a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
243735de3b38abbd6564082a819377673ee593744a6Kenny Root        }
244a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2455919ac6b4188285324646772501ef4b97b353cf4Kenny Root        public void link() throws RemoteException {
2465919ac6b4188285324646772501ef4b97b353cf4Kenny Root            getBinder().linkToDeath(this, 0);
2475919ac6b4188285324646772501ef4b97b353cf4Kenny Root        }
2485919ac6b4188285324646772501ef4b97b353cf4Kenny Root
2495919ac6b4188285324646772501ef4b97b353cf4Kenny Root        public void unlink() {
250735de3b38abbd6564082a819377673ee593744a6Kenny Root            getBinder().unlinkToDeath(this, 0);
251a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
25238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
25338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        @Override
25438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        public String toString() {
25538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            StringBuilder sb = new StringBuilder("ObbState{");
25638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append("filename=");
25738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(filename);
25838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(",token=");
25938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(token.toString());
26038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(",callerUid=");
26138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(callerUid);
26238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append('}');
26338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return sb.toString();
26438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
265a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
266a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
267a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // OBB Action Handler
268a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private ObbActionHandler mObbActionHandler;
269a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
270a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // OBB action handler messages
271a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_RUN_ACTION = 1;
272a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_BOUND = 2;
273a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_UNBIND = 3;
274a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_RECONNECT = 4;
275af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private static final int OBB_FLUSH_MOUNT_STATE = 5;
276a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
277a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    /*
278a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * Default Container Service information
27902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root     */
280a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
281a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
282a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
283a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
284a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
285a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class DefaultContainerConnection implements ServiceConnection {
286a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void onServiceConnected(ComponentName name, IBinder service) {
287a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
288a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "onServiceConnected");
289a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
290a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
291a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
292a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
293a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void onServiceDisconnected(ComponentName name) {
294a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
295a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "onServiceDisconnected");
296a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
297a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    };
298a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
299a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // Used in the ObbActionHandler
300a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private IMediaContainerService mContainerService = null;
30102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
30202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    // Handler messages
303c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_PM_UPDATE = 1;
304c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_PM_DONE = 2;
305c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_MS = 3;
306c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int RETRY_UNMOUNT_DELAY = 30; // in ms
307c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int MAX_UNMOUNT_RETRIES = 4;
308c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
309c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    class UnmountCallBack {
31005105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final String path;
31105105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final boolean force;
31213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo        final boolean removeEncryption;
313c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        int retries;
314c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
31513c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo        UnmountCallBack(String path, boolean force, boolean removeEncryption) {
316c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            retries = 0;
317c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            this.path = path;
318c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            this.force = force;
31913c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            this.removeEncryption = removeEncryption;
320c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        }
3210eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3220eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        void handleFinished() {
323a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path);
32413c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            doUnmountVolume(path, true, removeEncryption);
3250eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
3260eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
3270eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3280eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    class UmsEnableCallBack extends UnmountCallBack {
32905105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final String method;
3300eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3310eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        UmsEnableCallBack(String path, String method, boolean force) {
33213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            super(path, force, false);
3330eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            this.method = method;
3340eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
3350eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3360eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        @Override
3370eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        void handleFinished() {
3380eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            super.handleFinished();
3390eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            doShareUnshareVolume(path, method, true);
3400eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
341c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    }
342c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
3436ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    class ShutdownCallBack extends UnmountCallBack {
3446ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        IMountShutdownObserver observer;
3456ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        ShutdownCallBack(String path, IMountShutdownObserver observer) {
34613c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            super(path, true, false);
3476ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            this.observer = observer;
3486ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        }
3496ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3506ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        @Override
3516ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        void handleFinished() {
35213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            int ret = doUnmountVolume(path, true, removeEncryption);
3536ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            if (observer != null) {
3546ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                try {
3556ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    observer.onShutDownComplete(ret);
3566ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                } catch (RemoteException e) {
357a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.w(TAG, "RemoteException when shutting down");
3586ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                }
3596ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            }
3606ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        }
3616ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    }
3626ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3635f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler    class MountServiceHandler extends Handler {
364c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>();
365e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        boolean mUpdatingStatus = false;
3666ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3675f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        MountServiceHandler(Looper l) {
3685f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler            super(l);
3695f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        }
3705f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler
3715af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
372c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        public void handleMessage(Message msg) {
373c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            switch (msg.what) {
374c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                case H_UNMOUNT_PM_UPDATE: {
375a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_UPDATE");
376c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    UnmountCallBack ucb = (UnmountCallBack) msg.obj;
377c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    mForceUnmounts.add(ucb);
378a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, " registered = " + mUpdatingStatus);
3796ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    // Register only if needed.
380e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                    if (!mUpdatingStatus) {
381a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        if (DEBUG_UNMOUNT) Slog.i(TAG, "Updating external media status on PackageManager");
382e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                        mUpdatingStatus = true;
383e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                        mPms.updateExternalMediaStatus(false, true);
384c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    }
385c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
386c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
387c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                case H_UNMOUNT_PM_DONE: {
388a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_DONE");
389a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "Updated status. Processing requests");
390e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                    mUpdatingStatus = false;
3916ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int size = mForceUnmounts.size();
3926ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int sizeArr[] = new int[size];
3936ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int sizeArrN = 0;
3947af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    // Kill processes holding references first
3957af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    ActivityManagerService ams = (ActivityManagerService)
3967af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    ServiceManager.getService("activity");
3976ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    for (int i = 0; i < size; i++) {
3986ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        UnmountCallBack ucb = mForceUnmounts.get(i);
3996ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        String path = ucb.path;
4006ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        boolean done = false;
4016ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        if (!ucb.force) {
402c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                            done = true;
403c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        } else {
4046ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            int pids[] = getStorageUsers(path);
4056ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            if (pids == null || pids.length == 0) {
4066ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                                done = true;
4076ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            } else {
4086ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                                // Eliminate system process here?
409648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn                                ams.killPids(pids, "unmount media", true);
4107af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                // Confirm if file references have been freed.
4117af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                pids = getStorageUsers(path);
4127af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                if (pids == null || pids.length == 0) {
4137af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    done = true;
414c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                                }
415c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                            }
416c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        }
4177af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                        if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) {
4187af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            // Retry again
4197af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            Slog.i(TAG, "Retrying to kill storage users again");
4207af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            mHandler.sendMessageDelayed(
4217af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    mHandler.obtainMessage(H_UNMOUNT_PM_DONE,
4227af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                            ucb.retries++),
4237af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    RETRY_UNMOUNT_DELAY);
424c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        } else {
4256ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            if (ucb.retries >= MAX_UNMOUNT_RETRIES) {
4267af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                Slog.i(TAG, "Failed to unmount media inspite of " +
4277af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                        MAX_UNMOUNT_RETRIES + " retries. Forcibly killing processes now");
4286ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            }
4297af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            sizeArr[sizeArrN++] = i;
4307af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS,
4317af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    ucb));
432c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        }
433c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    }
4346ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    // Remove already processed elements from list.
4356ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    for (int i = (sizeArrN-1); i >= 0; i--) {
4366ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        mForceUnmounts.remove(sizeArr[i]);
4376ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    }
438c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
439c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
440c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                case H_UNMOUNT_MS : {
441a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_MS");
442c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    UnmountCallBack ucb = (UnmountCallBack) msg.obj;
4430eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                    ucb.handleFinished();
444c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
445c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
446c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            }
447c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        }
448c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    };
4495f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler    final private HandlerThread mHandlerThread;
4505f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler    final private Handler mHandler;
451c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
45251a573c76737733638c475f52e441c814e6645ccKenny Root    void waitForAsecScan() {
45351a573c76737733638c475f52e441c814e6645ccKenny Root        waitForLatch(mAsecsScanned);
45451a573c76737733638c475f52e441c814e6645ccKenny Root    }
45551a573c76737733638c475f52e441c814e6645ccKenny Root
456207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void waitForReady() {
45751a573c76737733638c475f52e441c814e6645ccKenny Root        waitForLatch(mConnectedSignal);
45851a573c76737733638c475f52e441c814e6645ccKenny Root    }
45951a573c76737733638c475f52e441c814e6645ccKenny Root
46051a573c76737733638c475f52e441c814e6645ccKenny Root    private void waitForLatch(CountDownLatch latch) {
46151a573c76737733638c475f52e441c814e6645ccKenny Root        if (latch == null) {
46251a573c76737733638c475f52e441c814e6645ccKenny Root            return;
46351a573c76737733638c475f52e441c814e6645ccKenny Root        }
46451a573c76737733638c475f52e441c814e6645ccKenny Root
46551a573c76737733638c475f52e441c814e6645ccKenny Root        for (;;) {
46651a573c76737733638c475f52e441c814e6645ccKenny Root            try {
46751a573c76737733638c475f52e441c814e6645ccKenny Root                if (latch.await(5000, TimeUnit.MILLISECONDS)) {
468207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    return;
46951a573c76737733638c475f52e441c814e6645ccKenny Root                } else {
47051a573c76737733638c475f52e441c814e6645ccKenny Root                    Slog.w(TAG, "Thread " + Thread.currentThread().getName()
47151a573c76737733638c475f52e441c814e6645ccKenny Root                            + " still waiting for MountService ready...");
472207e538350665cea00e1aa70b8094beca4a34e45San Mehat                }
47351a573c76737733638c475f52e441c814e6645ccKenny Root            } catch (InterruptedException e) {
47451a573c76737733638c475f52e441c814e6645ccKenny Root                Slog.w(TAG, "Interrupt while waiting for MountService to be ready.");
475207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
476207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
4771f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat    }
47802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
479444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
4805af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
48291c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat            String action = intent.getAction();
48391c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
48491c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat            if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
485207e538350665cea00e1aa70b8094beca4a34e45San Mehat                mBooted = true;
48622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
487c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                /*
488c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                 * In the simulator, we need to broadcast a volume mounted event
489c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                 * to make the media scanner run.
490c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                 */
491c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
49284338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                    notifyVolumeStateChange(null, "/sdcard", VolumeState.NoMedia,
49384338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                            VolumeState.Mounted);
494c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                    return;
495c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                }
496fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                new Thread() {
4975af0b916f850486cff4797355bf9e7dc3352fe00Jason parks                    @Override
498fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                    public void run() {
499fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                        try {
50084338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                            // it is not safe to call vold with mVolumeStates locked
50184338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                            // so we make a copy of the paths and states and process them
50284338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                            // outside the lock
503fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey                            String[] paths;
504fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey                            String[] states;
50584338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                            int count;
5067fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                            synchronized (mVolumeStates) {
50784338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                Set<String> keys = mVolumeStates.keySet();
50884338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                count = keys.size();
509444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo                                paths = keys.toArray(new String[count]);
51084338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                states = new String[count];
51184338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                for (int i = 0; i < count; i++) {
51284338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                    states[i] = mVolumeStates.get(paths[i]);
51384338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                }
51484338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                            }
51584338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood
51684338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                            for (int i = 0; i < count; i++) {
51784338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                String path = paths[i];
51884338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                String state = states[i];
51984338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood
52084338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                if (state.equals(Environment.MEDIA_UNMOUNTED)) {
52184338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                    int rc = doMountVolume(path);
52284338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                    if (rc != StorageResultCode.OperationSucceeded) {
52384338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                        Slog.e(TAG, String.format("Boot-time mount failed (%d)",
52484338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                                rc));
5257fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                                    }
52684338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                } else if (state.equals(Environment.MEDIA_SHARED)) {
52784338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                    /*
52884338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                     * Bootstrap UMS enabled state since vold indicates
52984338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                     * the volume is shared (runtime restart while ums enabled)
53084338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                     */
53184338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                    notifyVolumeStateChange(null, path, VolumeState.NoMedia,
53284338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood                                            VolumeState.Shared);
533fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                                }
534fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                            }
5356a254403235196692b1769d2fe281b0852c0cc25San Mehat
53680e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood                            /* notify external storage has mounted to trigger media scanner */
53780e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood                            if (mEmulateExternalStorage) {
53880e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood                                notifyVolumeStateChange(null,
53980e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood                                        Environment.getExternalStorageDirectory().getPath(),
54080e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood                                        VolumeState.NoMedia, VolumeState.Mounted);
54180e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood                            }
54280e0a416a6f8d70d3f55614695fb430f914371bcMike Lockwood
5436a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                            /*
5446a254403235196692b1769d2fe281b0852c0cc25San Mehat                             * If UMS was connected on boot, send the connected event
5456a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                             * now that we're up.
5466a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                             */
5476a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                            if (mSendUmsConnectedOnBoot) {
5486a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                                sendUmsIntent(true);
5496a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                                mSendUmsConnectedOnBoot = false;
5506a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                            }
551fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                        } catch (Exception ex) {
552a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.e(TAG, "Boot-time mount exception", ex);
553fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                        }
554207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    }
555fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                }.start();
556ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood            } else if (action.equals(UsbManager.ACTION_USB_STATE)) {
557ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood                boolean available = (intent.getBooleanExtra(UsbManager.USB_CONNECTED, false) &&
558ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood                        intent.getBooleanExtra(UsbManager.USB_FUNCTION_MASS_STORAGE, false));
559ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood                notifyShareAvailabilityChange(available);
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
5634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private final class MountServiceBinderListener implements IBinder.DeathRecipient {
5644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        final IMountServiceListener mListener;
56591c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
5664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        MountServiceBinderListener(IMountServiceListener listener) {
5674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mListener = listener;
56802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
56991c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat        }
57091c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
5714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public void binderDied() {
572a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!");
573a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            synchronized (mListeners) {
5744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListeners.remove(this);
5754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListener.asBinder().unlinkToDeath(this, 0);
57691c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat            }
57791c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat        }
57891c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat    }
57991c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
5800eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private void doShareUnshareVolume(String path, String method, boolean enable) {
5814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        // TODO: Add support for multiple share methods
5824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (!method.equals("ums")) {
5834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            throw new IllegalArgumentException(String.format("Method %s not supported", method));
5847fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
587dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("volume", enable ? "share" : "unshare", path, method);
5884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
589a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Failed to share/unshare", e);
59022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
593207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void updatePublicVolumeState(String path, String state) {
5947fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood        String oldState;
5957fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood        synchronized(mVolumeStates) {
5967fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            oldState = mVolumeStates.put(path, state);
5977fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
5987fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood        if (state.equals(oldState)) {
5997fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            Slog.w(TAG, String.format("Duplicate state transition (%s -> %s) for %s",
6007fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    state, state, path));
601b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return;
602b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
603af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
6047fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood        Slog.d(TAG, "volume state changed for " + path + " (" + oldState + " -> " + state + ")");
6057fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood
6067fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood        if (path.equals(mExternalStoragePath)) {
6077fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            // Update state on PackageManager, but only of real events
6087fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            if (!mEmulateExternalStorage) {
6097fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                if (Environment.MEDIA_UNMOUNTED.equals(state)) {
6107fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    mPms.updateExternalMediaStatus(false, false);
6117fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood
6127fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    /*
6137fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * Some OBBs might have been unmounted when this volume was
6147fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * unmounted, so send a message to the handler to let it know to
6157fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * remove those from the list of mounted OBBS.
6167fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     */
6177fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
6187fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                            OBB_FLUSH_MOUNT_STATE, path));
6197fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                } else if (Environment.MEDIA_MOUNTED.equals(state)) {
6207fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    mPms.updateExternalMediaStatus(true, false);
6217fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                }
62203559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood            }
6238a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
6244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
6254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for (int i = mListeners.size() -1; i >= 0; i--) {
6264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                MountServiceBinderListener bl = mListeners.get(i);
6274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                try {
628b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    bl.mListener.onStorageStateChanged(path, oldState, state);
6294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (RemoteException rex) {
630a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener dead");
6314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(i);
6324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (Exception ex) {
633a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener failed", ex);
6344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
63922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    /**
64022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     *
64122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     * Callback from NativeDaemonConnector
64222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     */
64322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    public void onDaemonConnected() {
6445b77dab23469273d41f9c530d947ac055765e6eaSan Mehat        /*
6455b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         * Since we'll be calling back into the NativeDaemonConnector,
6465b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         * we need to do our work in a new thread.
6475b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         */
64851a573c76737733638c475f52e441c814e6645ccKenny Root        new Thread("MountService#onDaemonConnected") {
6495af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            @Override
6507fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            public void run() {
6515b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                /**
6525b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                 * Determine media state and UMS detection status
6535b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                 */
6547fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                try {
655dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                    final String[] vols = NativeDaemonEvent.filterMessageList(
656dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                            mConnector.executeForList("volume", "list"),
657dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                            VoldResponseCode.VolumeListResult);
6585b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                    for (String volstr : vols) {
6595b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        String[] tok = volstr.split(" ");
6605b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        // FMT: <label> <mountpoint> <state>
6617fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        String path = tok[1];
6627fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        String state = Environment.MEDIA_REMOVED;
6637fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood
6645b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        int st = Integer.parseInt(tok[2]);
6655b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        if (st == VolumeState.NoMedia) {
6665b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_REMOVED;
6675b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Idle) {
668207e538350665cea00e1aa70b8094beca4a34e45San Mehat                            state = Environment.MEDIA_UNMOUNTED;
6695b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Mounted) {
6705b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_MOUNTED;
671a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.i(TAG, "Media already mounted on daemon connection");
6725b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Shared) {
6735b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_SHARED;
674a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.i(TAG, "Media shared on daemon connection");
6755b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else {
6765b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            throw new Exception(String.format("Unexpected state %d", st));
6777fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                        }
6787fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood
6797fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        if (state != null) {
6807fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                            if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state);
6817fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                            updatePublicVolumeState(path, state);
6827fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        }
683c2a39471642e31d7350910612e40d078b825173aSan Mehat                    }
6845b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                } catch (Exception e) {
685a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Error processing initial volume state", e);
6867fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    updatePublicVolumeState(mExternalStoragePath, Environment.MEDIA_REMOVED);
6877fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                }
6887fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
689207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
6909ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                 * Now that we've done our initialization, release
691207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * the hounds!
692207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
69351a573c76737733638c475f52e441c814e6645ccKenny Root                mConnectedSignal.countDown();
69451a573c76737733638c475f52e441c814e6645ccKenny Root                mConnectedSignal = null;
69551a573c76737733638c475f52e441c814e6645ccKenny Root
69651a573c76737733638c475f52e441c814e6645ccKenny Root                // Let package manager load internal ASECs.
69751a573c76737733638c475f52e441c814e6645ccKenny Root                mPms.scanAvailableAsecs();
69851a573c76737733638c475f52e441c814e6645ccKenny Root
69951a573c76737733638c475f52e441c814e6645ccKenny Root                // Notify people waiting for ASECs to be scanned that it's done.
70051a573c76737733638c475f52e441c814e6645ccKenny Root                mAsecsScanned.countDown();
70151a573c76737733638c475f52e441c814e6645ccKenny Root                mAsecsScanned = null;
7027fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            }
7037fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }.start();
7047fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
7057fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
70622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    /**
70722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     * Callback from NativeDaemonConnector
70822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     */
70922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    public boolean onEvent(int code, String raw, String[] cooked) {
7108a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        if (DEBUG_EVENTS) {
7118a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            StringBuilder builder = new StringBuilder();
7128a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            builder.append("onEvent::");
7138a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            builder.append(" raw= " + raw);
7148a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            if (cooked != null) {
7158a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                builder.append(" cooked = " );
7168a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                for (String str : cooked) {
7178a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                    builder.append(" " + str);
7188a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                }
7198a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            }
720a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.i(TAG, builder.toString());
7218a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
72222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        if (code == VoldResponseCode.VolumeStateChange) {
7234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            /*
7244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * One of the volumes we're managing has changed state.
7254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * Format: "NNN Volume <label> <path> state changed
7264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * from <old_#> (<old_str>) to <new_#> (<new_str>)"
7274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             */
72822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            notifyVolumeStateChange(
72922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat                    cooked[2], cooked[3], Integer.parseInt(cooked[7]),
73022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat                            Integer.parseInt(cooked[10]));
7314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } else if ((code == VoldResponseCode.VolumeDiskInserted) ||
7324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                   (code == VoldResponseCode.VolumeDiskRemoved) ||
7334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                   (code == VoldResponseCode.VolumeBadRemoval)) {
73422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
73522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
73622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
737a5250c93928e256738125b265e10c96c3575597eMike Lockwood            String action = null;
7384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            final String label = cooked[2];
7394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            final String path = cooked[3];
7404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            int major = -1;
7414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            int minor = -1;
7424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
7434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            try {
7444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                String devComp = cooked[6].substring(1, cooked[6].length() -1);
7454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                String[] devTok = devComp.split(":");
7464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                major = Integer.parseInt(devTok[0]);
7474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                minor = Integer.parseInt(devTok[1]);
7484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } catch (Exception ex) {
749a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to parse major/minor", ex);
7504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
7514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
7524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            if (code == VoldResponseCode.VolumeDiskInserted) {
7534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                new Thread() {
7545af0b916f850486cff4797355bf9e7dc3352fe00Jason parks                    @Override
7554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    public void run() {
7564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        try {
7574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                            int rc;
758b104340496e3a531e26c8f428c808eca0e039f50San Mehat                            if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
759a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                                Slog.w(TAG, String.format("Insertion mount failed (%d)", rc));
7604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                            }
7614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        } catch (Exception ex) {
762a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.w(TAG, "Failed to mount media on insertion", ex);
7634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        }
7644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    }
7654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }.start();
7664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else if (code == VoldResponseCode.VolumeDiskRemoved) {
7674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /*
7684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                 * This event gets trumped if we're already in BAD_REMOVAL state
7694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                 */
7704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
7714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    return true;
7724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
7734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /* Send the media unmounted event first */
774a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
7754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
776a5250c93928e256738125b265e10c96c3575597eMike Lockwood                sendStorageIntent(Environment.MEDIA_UNMOUNTED, path);
7774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
778a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed");
7794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
780a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_REMOVED;
7814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else if (code == VoldResponseCode.VolumeBadRemoval) {
782a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
7834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /* Send the media unmounted event first */
7844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
785a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_UNMOUNTED;
7864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
787a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal");
7884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);
789a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_BAD_REMOVAL;
7904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else {
791a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Unknown code {%d}", code));
7924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
793a5250c93928e256738125b265e10c96c3575597eMike Lockwood
794a5250c93928e256738125b265e10c96c3575597eMike Lockwood            if (action != null) {
795a5250c93928e256738125b265e10c96c3575597eMike Lockwood                sendStorageIntent(action, path);
796a5250c93928e256738125b265e10c96c3575597eMike Lockwood            }
79722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        } else {
79822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            return false;
79922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
8004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
8015f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        return true;
80222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
80322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
804207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void notifyVolumeStateChange(String label, String path, int oldState, int newState) {
8054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        String vs = getVolumeState(path);
806a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChanged::" + vs);
8074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
808a5250c93928e256738125b265e10c96c3575597eMike Lockwood        String action = null;
8097fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
810bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood        if (oldState == VolumeState.Shared && newState != oldState) {
811a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent");
812a5250c93928e256738125b265e10c96c3575597eMike Lockwood            sendStorageIntent(Intent.ACTION_MEDIA_UNSHARED,  path);
813bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood        }
814bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood
8157fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        if (newState == VolumeState.Init) {
8167fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.NoMedia) {
8177fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            // NoMedia is handled via Disk Remove events
8187fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Idle) {
8195fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat            /*
8205fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or
8215fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             * if we're in the process of enabling UMS
8225fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             */
8234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            if (!vs.equals(
8244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    Environment.MEDIA_BAD_REMOVAL) && !vs.equals(
8254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                            Environment.MEDIA_NOFS) && !vs.equals(
8260eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                                    Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) {
827a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable");
8284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
829a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_UNMOUNTED;
8307fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            }
8317fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Pending) {
8327fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Checking) {
833a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking");
8344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            updatePublicVolumeState(path, Environment.MEDIA_CHECKING);
835a5250c93928e256738125b265e10c96c3575597eMike Lockwood            action = Intent.ACTION_MEDIA_CHECKING;
8367fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Mounted) {
837a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted");
8384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            updatePublicVolumeState(path, Environment.MEDIA_MOUNTED);
839a5250c93928e256738125b265e10c96c3575597eMike Lockwood            action = Intent.ACTION_MEDIA_MOUNTED;
8407fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Unmounting) {
841a5250c93928e256738125b265e10c96c3575597eMike Lockwood            action = Intent.ACTION_MEDIA_EJECT;
8427fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Formatting) {
8437fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Shared) {
844a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted");
8454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            /* Send the media unmounted event first */
8464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
847a5250c93928e256738125b265e10c96c3575597eMike Lockwood            sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, path);
8484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
849a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared");
8504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            updatePublicVolumeState(path, Environment.MEDIA_SHARED);
851a5250c93928e256738125b265e10c96c3575597eMike Lockwood            action = Intent.ACTION_MEDIA_SHARED;
852a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent");
8537fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.SharedMnt) {
854a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Live shared mounts not supported yet!");
8554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            return;
8567fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else {
857a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Unhandled VolumeState {" + newState + "}");
8587fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
8597fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
860a5250c93928e256738125b265e10c96c3575597eMike Lockwood        if (action != null) {
861a5250c93928e256738125b265e10c96c3575597eMike Lockwood            sendStorageIntent(action, path);
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
865207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private int doMountVolume(String path) {
866b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
867207e538350665cea00e1aa70b8094beca4a34e45San Mehat
868a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path);
869207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
870dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("volume", "mount", path);
871207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
872207e538350665cea00e1aa70b8094beca4a34e45San Mehat            /*
873207e538350665cea00e1aa70b8094beca4a34e45San Mehat             * Mount failed for some reason
874207e538350665cea00e1aa70b8094beca4a34e45San Mehat             */
875a5250c93928e256738125b265e10c96c3575597eMike Lockwood            String action = null;
876207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
877207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedNoMedia) {
878207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
879207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Attempt to mount but no media inserted
880207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
881b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedNoMedia;
882207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaBlank) {
883a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs");
884207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
885207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Media is blank or does not contain a supported filesystem
886207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
887207e538350665cea00e1aa70b8094beca4a34e45San Mehat                updatePublicVolumeState(path, Environment.MEDIA_NOFS);
888a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_NOFS;
889b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedMediaBlank;
890207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
891a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state media corrupt");
892207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
893207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Volume consistency check failed
894207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
895207e538350665cea00e1aa70b8094beca4a34e45San Mehat                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
896a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_UNMOUNTABLE;
897b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedMediaCorrupt;
898207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
899b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedInternalError;
900207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
901207e538350665cea00e1aa70b8094beca4a34e45San Mehat
902207e538350665cea00e1aa70b8094beca4a34e45San Mehat            /*
903207e538350665cea00e1aa70b8094beca4a34e45San Mehat             * Send broadcast intent (if required for the failure)
904207e538350665cea00e1aa70b8094beca4a34e45San Mehat             */
905a5250c93928e256738125b265e10c96c3575597eMike Lockwood            if (action != null) {
906a5250c93928e256738125b265e10c96c3575597eMike Lockwood                sendStorageIntent(action, path);
907207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
908207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
909207e538350665cea00e1aa70b8094beca4a34e45San Mehat
910207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return rc;
911207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
912207e538350665cea00e1aa70b8094beca4a34e45San Mehat
913c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    /*
914c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * If force is not set, we do not unmount if there are
915c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * processes holding references to the volume about to be unmounted.
916c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * If force is set, all the processes holding references need to be
917c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * killed via the ActivityManager before actually unmounting the volume.
918c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * This might even take a while and might be retried after timed delays
919c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * to make sure we dont end up in an instable state and kill some core
920c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * processes.
92113c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo     * If removeEncryption is set, force is implied, and the system will remove any encryption
92213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo     * mapping set on the volume when unmounting.
923c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     */
92413c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo    private int doUnmountVolume(String path, boolean force, boolean removeEncryption) {
92559443a673a736978361dc341f41ce4e9dae053a0San Mehat        if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
926207e538350665cea00e1aa70b8094beca4a34e45San Mehat            return VoldResponseCode.OpFailedVolNotMounted;
927207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
928aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
929aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
930aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
931aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
932aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
933aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
934aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
935aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
936aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
937c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        // Redundant probably. But no harm in updating state again.
938e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        mPms.updateExternalMediaStatus(false, false);
939207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
940dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            final Command cmd = new Command("volume", "unmount", path);
941dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            if (removeEncryption) {
942dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                cmd.appendArg("force_and_revert");
943dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            } else if (force) {
944dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                cmd.appendArg("force");
945dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            }
946dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute(cmd);
947e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            // We unmounted the volume. None of the asec containers are available now.
948e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            synchronized (mAsecMountSet) {
949e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                mAsecMountSet.clear();
950e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            }
951b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return StorageResultCode.OperationSucceeded;
952207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
953207e538350665cea00e1aa70b8094beca4a34e45San Mehat            // Don't worry about mismatch in PackageManager since the
954207e538350665cea00e1aa70b8094beca4a34e45San Mehat            // call back will handle the status changes any way.
955207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
956207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedVolNotMounted) {
957a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageNotMounted;
958d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else if (code == VoldResponseCode.OpFailedStorageBusy) {
959d970998b0d489774ad1c5b94b47d233912f00214San Mehat                return StorageResultCode.OperationFailedStorageBusy;
960207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
961b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedInternalError;
962207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
963207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
964207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
965207e538350665cea00e1aa70b8094beca4a34e45San Mehat
966207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private int doFormatVolume(String path) {
967207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
968dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("volume", "format", path);
969b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return StorageResultCode.OperationSucceeded;
970207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
971207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
972207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedNoMedia) {
973b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedNoMedia;
974207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
975b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedMediaCorrupt;
976207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
977b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedInternalError;
978207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
979207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
980207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
981207e538350665cea00e1aa70b8094beca4a34e45San Mehat
982b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private boolean doGetVolumeShared(String path, String method) {
983dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
984a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
985dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("volume", "shared", path, method);
986a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException ex) {
987a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            Slog.e(TAG, "Failed to read response to volume shared " + path + " " + method);
988a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            return false;
989a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
990b104340496e3a531e26c8f428c808eca0e039f50San Mehat
991dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        if (event.getCode() == VoldResponseCode.ShareEnabledResult) {
992dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return event.getMessage().endsWith("enabled");
993dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        } else {
994dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return false;
995b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
996b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
997b104340496e3a531e26c8f428c808eca0e039f50San Mehat
998ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood    private void notifyShareAvailabilityChange(final boolean avail) {
9994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
1000ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood            mUmsAvailable = avail;
10014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for (int i = mListeners.size() -1; i >= 0; i--) {
10024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                MountServiceBinderListener bl = mListeners.get(i);
10031f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                try {
1004b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    bl.mListener.onUsbMassStorageConnectionChanged(avail);
10054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (RemoteException rex) {
1006a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener dead");
10074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(i);
10081f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                } catch (Exception ex) {
1009a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener failed", ex);
10101f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                }
10111f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat            }
10124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        }
10137fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
1014207e538350665cea00e1aa70b8094beca4a34e45San Mehat        if (mBooted == true) {
10156a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat            sendUmsIntent(avail);
10166a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat        } else {
10176a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat            mSendUmsConnectedOnBoot = avail;
10181f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat        }
10192fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat
10202fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat        final String path = Environment.getExternalStorageDirectory().getPath();
10212fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat        if (avail == false && getVolumeState(path).equals(Environment.MEDIA_SHARED)) {
10222fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            /*
10232fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat             * USB mass storage disconnected while enabled
10242fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat             */
10252fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            new Thread() {
10265af0b916f850486cff4797355bf9e7dc3352fe00Jason parks                @Override
10272fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                public void run() {
10282fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    try {
10292fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        int rc;
1030a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        Slog.w(TAG, "Disabling UMS after cable disconnect");
10312fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        doShareUnshareVolume(path, "ums", false);
10322fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
1033a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.e(TAG, String.format(
10342fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                                    "Failed to remount {%s} on UMS enabled-disconnect (%d)",
10352fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                                            path, rc));
10362fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        }
10372fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    } catch (Exception ex) {
1038a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        Slog.w(TAG, "Failed to mount media on UMS enabled-disconnect", ex);
10392fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    }
10402fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                }
10412fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            }.start();
10422fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat        }
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1045a5250c93928e256738125b265e10c96c3575597eMike Lockwood    private void sendStorageIntent(String action, String path) {
1046a5250c93928e256738125b265e10c96c3575597eMike Lockwood        Intent intent = new Intent(action, Uri.parse("file://" + path));
1047a5250c93928e256738125b265e10c96c3575597eMike Lockwood        // add StorageVolume extra
1048a5250c93928e256738125b265e10c96c3575597eMike Lockwood        intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mVolumeMap.get(path));
1049a5250c93928e256738125b265e10c96c3575597eMike Lockwood        Slog.d(TAG, "sendStorageIntent " + intent);
10505ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1051a5250c93928e256738125b265e10c96c3575597eMike Lockwood    }
1052a5250c93928e256738125b265e10c96c3575597eMike Lockwood
10536a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private void sendUmsIntent(boolean c) {
10545ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        mContext.sendBroadcastAsUser(
10555ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn                new Intent((c ? Intent.ACTION_UMS_CONNECTED : Intent.ACTION_UMS_DISCONNECTED)),
10565ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn                UserHandle.ALL);
10576a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    }
10586a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat
1059207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void validatePermission(String perm) {
10604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
10614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            throw new SecurityException(String.format("Requires %s permission", perm));
10624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        }
10637fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
10647fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
10652f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    // Storage list XML tags
10662f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    private static final String TAG_STORAGE_LIST = "StorageList";
10672f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    private static final String TAG_STORAGE = "storage";
10682f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
106913fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio    private void readStorageList() {
107013fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio        Resources resources = mContext.getResources();
107113fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio
10722f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        int id = com.android.internal.R.xml.storage_list;
10732f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        XmlResourceParser parser = resources.getXml(id);
10742f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        AttributeSet attrs = Xml.asAttributeSet(parser);
10752f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
10762f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        try {
10772f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            XmlUtils.beginDocument(parser, TAG_STORAGE_LIST);
10782f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            while (true) {
10792f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                XmlUtils.nextElement(parser);
10802f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
10812f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                String element = parser.getName();
10822f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                if (element == null) break;
10832f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
10842f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                if (TAG_STORAGE.equals(element)) {
10852f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    TypedArray a = resources.obtainAttributes(attrs,
10862f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage);
10872f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
10882f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    CharSequence path = a.getText(
10892f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_mountPoint);
109013fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio                    int descriptionId = a.getResourceId(
109113fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio                            com.android.internal.R.styleable.Storage_storageDescription, -1);
10922f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    CharSequence description = a.getText(
10932f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_storageDescription);
10942f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    boolean primary = a.getBoolean(
10952f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_primary, false);
10962f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    boolean removable = a.getBoolean(
10972f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_removable, false);
10982f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    boolean emulated = a.getBoolean(
10992f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_emulated, false);
11002f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    int mtpReserve = a.getInt(
11012f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_mtpReserve, 0);
11028e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood                    boolean allowMassStorage = a.getBoolean(
11038e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood                            com.android.internal.R.styleable.Storage_allowMassStorage, false);
11047a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood                    // resource parser does not support longs, so XML value is in megabytes
11057a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood                    long maxFileSize = a.getInt(
11067a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood                            com.android.internal.R.styleable.Storage_maxFileSize, 0) * 1024L * 1024L;
11072f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
11082f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    Slog.d(TAG, "got storage path: " + path + " description: " + description +
11092f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            " primary: " + primary + " removable: " + removable +
11108e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood                            " emulated: " + emulated +  " mtpReserve: " + mtpReserve +
11117a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood                            " allowMassStorage: " + allowMassStorage +
11127a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood                            " maxFileSize: " + maxFileSize);
11132f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    if (path == null || description == null) {
11142f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        Slog.e(TAG, "path or description is null in readStorageList");
11152f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    } else {
1116a5250c93928e256738125b265e10c96c3575597eMike Lockwood                        String pathString = path.toString();
1117a5250c93928e256738125b265e10c96c3575597eMike Lockwood                        StorageVolume volume = new StorageVolume(pathString,
111813fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio                                descriptionId, removable, emulated,
11197a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood                                mtpReserve, allowMassStorage, maxFileSize);
11202f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        if (primary) {
11212f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            if (mPrimaryVolume == null) {
11222f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                                mPrimaryVolume = volume;
11232f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            } else {
11242f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                                Slog.e(TAG, "multiple primary volumes in storage list");
11252f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            }
11262f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        }
11272f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        if (mPrimaryVolume == volume) {
11282f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            // primay volume must be first
11292f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            mVolumes.add(0, volume);
11302f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        } else {
11312f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            mVolumes.add(volume);
11322f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        }
1133a5250c93928e256738125b265e10c96c3575597eMike Lockwood                        mVolumeMap.put(pathString, volume);
11342f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    }
11352f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    a.recycle();
11362f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                }
11372f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            }
11382f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        } catch (XmlPullParserException e) {
11392f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            throw new RuntimeException(e);
11402f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        } catch (IOException e) {
11412f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            throw new RuntimeException(e);
11422f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        } finally {
1143fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood            // compute storage ID for each volume
1144fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood            int length = mVolumes.size();
1145fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood            for (int i = 0; i < length; i++) {
1146fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood                mVolumes.get(i).setStorageId(i);
1147fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood            }
11482f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            parser.close();
11492f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        }
11502f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    }
11512f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1153207e538350665cea00e1aa70b8094beca4a34e45San Mehat     * Constructs a new MountService instance
1154207e538350665cea00e1aa70b8094beca4a34e45San Mehat     *
1155207e538350665cea00e1aa70b8094beca4a34e45San Mehat     * @param context  Binder context for this service
1156207e538350665cea00e1aa70b8094beca4a34e45San Mehat     */
1157207e538350665cea00e1aa70b8094beca4a34e45San Mehat    public MountService(Context context) {
1158207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mContext = context;
115913fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio        readStorageList();
11602f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
11612f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        if (mPrimaryVolume != null) {
11622f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            mExternalStoragePath = mPrimaryVolume.getPath();
11632f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            mEmulateExternalStorage = mPrimaryVolume.isEmulated();
11642f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            if (mEmulateExternalStorage) {
11652f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                Slog.d(TAG, "using emulated external storage");
11662f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                mVolumeStates.put(mExternalStoragePath, Environment.MEDIA_MOUNTED);
11672f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            }
116803559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood        }
116903559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood
1170207e538350665cea00e1aa70b8094beca4a34e45San Mehat        // XXX: This will go away soon in favor of IMountServiceObserver
1171207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mPms = (PackageManagerService) ServiceManager.getService("package");
1172207e538350665cea00e1aa70b8094beca4a34e45San Mehat
1173ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood        IntentFilter filter = new IntentFilter();
1174ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood        filter.addAction(Intent.ACTION_BOOT_COMPLETED);
1175ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood        // don't bother monitoring USB if mass storage is not supported on our primary volume
1176ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood        if (mPrimaryVolume != null && mPrimaryVolume.allowMassStorage()) {
1177ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood            filter.addAction(UsbManager.ACTION_USB_STATE);
1178ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood        }
1179ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood        mContext.registerReceiver(mBroadcastReceiver, filter, null, null);
1180207e538350665cea00e1aa70b8094beca4a34e45San Mehat
11815f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandlerThread = new HandlerThread("MountService");
11825f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandlerThread.start();
11835f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandler = new MountServiceHandler(mHandlerThread.getLooper());
11845f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler
1185a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        // Add OBB Action Handler to MountService thread.
1186a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());
1187a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1188c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen        /*
1189305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * Create the connection to vold with a maximum queue of twice the
1190305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * amount of containers we'd ever expect to have. This keeps an
1191305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * "asec list" from blocking a thread repeatedly.
1192305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         */
1193470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt        mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25);
119451a573c76737733638c475f52e441c814e6645ccKenny Root
1195305bcbf0c961840c4505770d084a1caacc074dbbKenny Root        Thread thread = new Thread(mConnector, VOLD_TAG);
1196207e538350665cea00e1aa70b8094beca4a34e45San Mehat        thread.start();
1197fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey
119807714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root        // Add ourself to the Watchdog monitors if enabled.
119907714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root        if (WATCHDOG_ENABLE) {
120007714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root            Watchdog.getInstance().addMonitor(this);
120107714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root        }
1202207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
1203207e538350665cea00e1aa70b8094beca4a34e45San Mehat
1204207e538350665cea00e1aa70b8094beca4a34e45San Mehat    /**
12054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Exposed API calls below here
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12077fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
12084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public void registerListener(IMountServiceListener listener) {
12094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
12104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            MountServiceBinderListener bl = new MountServiceBinderListener(listener);
12114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            try {
12124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                listener.asBinder().linkToDeath(bl, 0);
12134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListeners.add(bl);
12144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } catch (RemoteException rex) {
1215a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to link to listener death");
12164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
12177fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public void unregisterListener(IMountServiceListener listener) {
12214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
12224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for(MountServiceBinderListener bl : mListeners) {
12234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                if (bl.mListener == listener) {
12244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(mListeners.indexOf(bl));
12255c25a2d338e9609d54e58cc1916c91cd8e9979abVairavan Srinivasan                    listener.asBinder().unlinkToDeath(bl, 0);
12264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    return;
12274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
12284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12326ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    public void shutdown(final IMountShutdownObserver observer) {
12334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.SHUTDOWN);
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1235a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        Slog.i(TAG, "Shutting down");
12367fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood        synchronized (mVolumeStates) {
12377fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            for (String path : mVolumeStates.keySet()) {
12387fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                String state = mVolumeStates.get(path);
12397fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood
12407fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                if (state.equals(Environment.MEDIA_SHARED)) {
12417fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    /*
12427fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * If the media is currently shared, unshare it.
12437fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * XXX: This is still dangerous!. We should not
12447fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * be rebooting at *all* if UMS is enabled, since
12457fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * the UMS host could have dirty FAT cache entries
12467fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * yet to flush.
12477fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     */
12487fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    setUsbMassStorageEnabled(false);
12497fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                } else if (state.equals(Environment.MEDIA_CHECKING)) {
12507fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    /*
12517fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * If the media is being checked, then we need to wait for
12527fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * it to complete before being able to proceed.
12537fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     */
12547fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    // XXX: @hackbod - Should we disable the ANR timer here?
12557fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    int retries = 30;
12567fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
12577fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        try {
12587fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                            Thread.sleep(1000);
12597fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        } catch (InterruptedException iex) {
12607fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                            Slog.e(TAG, "Interrupted while waiting for media", iex);
12617fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                            break;
12627fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        }
12637fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        state = Environment.getExternalStorageState();
12647fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    }
12657fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    if (retries == 0) {
12667fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        Slog.e(TAG, "Timed out waiting for media to check");
12677fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    }
12684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
12697fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
12707fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                if (state.equals(Environment.MEDIA_MOUNTED)) {
12717fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    // Post a unmount message.
12727fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    ShutdownCallBack ucb = new ShutdownCallBack(path, observer);
12737fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
12747fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                } else if (observer != null) {
12757fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    /*
12767fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * Observer is waiting for onShutDownComplete when we are done.
12777fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * Since nothing will be done send notification directly so shutdown
12787fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * sequence can continue.
12797fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     */
12807fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    try {
12817fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        observer.onShutDownComplete(StorageResultCode.OperationSucceeded);
12827fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    } catch (RemoteException e) {
12837fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        Slog.w(TAG, "RemoteException when shutting down");
12847fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    }
12857fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                }
12865d0db4d356346bee68aec9a124df70dbaa9aaed1Johan Alfven            }
12871f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat        }
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12900eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private boolean getUmsEnabling() {
12910eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        synchronized (mListeners) {
12920eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            return mUmsEnabling;
12930eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
12940eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
12950eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
12960eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private void setUmsEnabling(boolean enable) {
12970eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        synchronized (mListeners) {
1298fc71125104650c61ab5b04f4c943de761d58cba6Tony Wu            mUmsEnabling = enable;
12990eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
13000eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
13010eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
1302b104340496e3a531e26c8f428c808eca0e039f50San Mehat    public boolean isUsbMassStorageConnected() {
1303207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
13047fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
13050eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (getUmsEnabling()) {
1306b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return true;
1307b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
1308ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood        synchronized (mListeners) {
1309ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood            return mUmsAvailable;
1310ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood        }
13114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13130eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    public void setUsbMassStorageEnabled(boolean enable) {
1314207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
13150eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
13160eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
13170eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        // TODO: Add support for multiple share methods
1318b104340496e3a531e26c8f428c808eca0e039f50San Mehat
13190eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        /*
13200eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         * If the volume is mounted and we're enabling then unmount it
13210eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         */
13220eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        String path = Environment.getExternalStorageDirectory().getPath();
13230eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        String vs = getVolumeState(path);
13240eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        String method = "ums";
13250eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
13260eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            // Override for isUsbMassStorageEnabled()
13270eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            setUmsEnabling(enable);
13280eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true);
13290eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb));
13300eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            // Clear override
13310eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            setUmsEnabling(false);
13320eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
13330eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        /*
13340eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         * If we disabled UMS then mount the volume
13350eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         */
13360eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (!enable) {
13370eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            doShareUnshareVolume(path, method, enable);
13380eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
1339a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to remount " + path +
13400eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                        " after disabling share method " + method);
13410eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                /*
13420eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * Even though the mount failed, the unshare didn't so don't indicate an error.
13430eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * The mountVolume() call will have set the storage state and sent the necessary
13440eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * broadcasts.
13450eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 */
13460eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            }
13470eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
13484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1350b104340496e3a531e26c8f428c808eca0e039f50San Mehat    public boolean isUsbMassStorageEnabled() {
1351207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1352b104340496e3a531e26c8f428c808eca0e039f50San Mehat        return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums");
13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13549ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
13564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * @return state of the volume at the specified mount point
13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String getVolumeState(String mountPoint) {
13597fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood        synchronized (mVolumeStates) {
13607fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            String state = mVolumeStates.get(mountPoint);
13617fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            if (state == null) {
13627fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
136318db5c5690472f9da6ce2d580067307378675809Ken Sumrall                if (SystemProperties.get("vold.encrypt_progress").length() != 0) {
136418db5c5690472f9da6ce2d580067307378675809Ken Sumrall                    state = Environment.MEDIA_REMOVED;
136518db5c5690472f9da6ce2d580067307378675809Ken Sumrall                } else {
136618db5c5690472f9da6ce2d580067307378675809Ken Sumrall                    throw new IllegalArgumentException();
136718db5c5690472f9da6ce2d580067307378675809Ken Sumrall                }
13687fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            }
13694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
13707fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            return state;
13717fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood        }
13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1374e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root    public boolean isExternalStorageEmulated() {
1375e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root        return mEmulateExternalStorage;
1376e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root    }
1377e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root
13784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int mountVolume(String path) {
13794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1381207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1382207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return doMountVolume(path);
13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
138513c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo    public void unmountVolume(String path, boolean force, boolean removeEncryption) {
13864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1387207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13898a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        String volState = getVolumeState(path);
139013c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo        if (DEBUG_UNMOUNT) {
139113c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            Slog.i(TAG, "Unmounting " + path
139213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo                    + " force = " + force
139313c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo                    + " removeEncryption = " + removeEncryption);
139413c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo        }
13958a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        if (Environment.MEDIA_UNMOUNTED.equals(volState) ||
13968a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_REMOVED.equals(volState) ||
13978a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_SHARED.equals(volState) ||
13988a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_UNMOUNTABLE.equals(volState)) {
13998a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            // Media already unmounted or cannot be unmounted.
14008a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            // TODO return valid return code when adding observer call back.
14018a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            return;
14028a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
140313c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo        UnmountCallBack ucb = new UnmountCallBack(path, force, removeEncryption);
1404c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
14054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int formatVolume(String path) {
14084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1409207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1411207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return doFormatVolume(path);
14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14133697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1414ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood    public int[] getStorageUsers(String path) {
1415c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1416c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        waitForReady();
1417c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        try {
1418dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            final String[] r = NativeDaemonEvent.filterMessageList(
1419dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                    mConnector.executeForList("storage", "users", path),
1420dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                    VoldResponseCode.StorageUsersListResult);
1421dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey
1422c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            // FMT: <pid> <process name>
1423c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            int[] data = new int[r.length];
1424c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            for (int i = 0; i < r.length; i++) {
1425dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                String[] tok = r[i].split(" ");
1426c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                try {
1427c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                    data[i] = Integer.parseInt(tok[0]);
1428c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                } catch (NumberFormatException nfe) {
1429a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
1430c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                    return new int[0];
1431c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                }
1432c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            }
1433c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            return data;
1434c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        } catch (NativeDaemonConnectorException e) {
1435a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Failed to retrieve storage users list", e);
1436c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            return new int[0];
1437c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        }
1438c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat    }
1439c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat
1440b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private void warnOnNotMounted() {
1441b104340496e3a531e26c8f428c808eca0e039f50San Mehat        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
1442a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.w(TAG, "getSecureContainerList() called when storage not mounted");
1443b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
1444b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
1445b104340496e3a531e26c8f428c808eca0e039f50San Mehat
14464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String[] getSecureContainerList() {
14474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
1448207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1449b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1450f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
14514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1452dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return NativeDaemonEvent.filterMessageList(
1453dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                    mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
14544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
14554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            return new String[0];
145602735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
14573697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
14583697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
14596dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root    public int createSecureContainer(String id, int sizeMb, String fstype, String key,
14606dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root            int ownerUid, boolean external) {
14614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_CREATE);
1462207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1463b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
14644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1465b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
14664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
14676dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root            mConnector.execute("asec", "create", id, sizeMb, fstype, key, ownerUid,
14686dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root                    external ? "1" : "0");
14694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1470b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
147102735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1472a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1473a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        if (rc == StorageResultCode.OperationSucceeded) {
1474a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            synchronized (mAsecMountSet) {
1475a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                mAsecMountSet.add(id);
1476a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1477a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
14784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
14793697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
14803697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
14814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int finalizeSecureContainer(String id) {
14824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_CREATE);
1483b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
14844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1485b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
14864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1487dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("asec", "finalize", id);
1488a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            /*
1489a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             * Finalization does a remount, so no need
1490a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             * to update mAsecMountSet
1491a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             */
14926dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        } catch (NativeDaemonConnectorException e) {
14936dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root            rc = StorageResultCode.OperationFailedInternalError;
14946dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        }
14956dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        return rc;
14966dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root    }
14976dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root
14986dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root    public int fixPermissionsSecureContainer(String id, int gid, String filename) {
14996dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        validatePermission(android.Manifest.permission.ASEC_CREATE);
15006dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        warnOnNotMounted();
15016dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root
15026dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        int rc = StorageResultCode.OperationSucceeded;
15036dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        try {
15046dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root            mConnector.execute("asec", "fixperms", id, gid, filename);
15056dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root            /*
15066dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root             * Fix permissions does a remount, so no need to update
15076dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root             * mAsecMountSet
15086dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root             */
15094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1510b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
151102735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
15124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
15133697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
15143697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1515d970998b0d489774ad1c5b94b47d233912f00214San Mehat    public int destroySecureContainer(String id, boolean force) {
15164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_DESTROY);
1517207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1518b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1519f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
1520aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
1521aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
1522aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
1523aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
1524aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
1525aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
1526aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
1527aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
1528b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
15294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1530dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            final Command cmd = new Command("asec", "destroy", id);
1531dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            if (force) {
1532dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                cmd.appendArg("force");
1533dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            }
1534dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute(cmd);
15354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1536d970998b0d489774ad1c5b94b47d233912f00214San Mehat            int code = e.getCode();
1537d970998b0d489774ad1c5b94b47d233912f00214San Mehat            if (code == VoldResponseCode.OpFailedStorageBusy) {
1538d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedStorageBusy;
1539d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else {
1540d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedInternalError;
1541d970998b0d489774ad1c5b94b47d233912f00214San Mehat            }
154202735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1543a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1544a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        if (rc == StorageResultCode.OperationSucceeded) {
1545a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            synchronized (mAsecMountSet) {
1546a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                if (mAsecMountSet.contains(id)) {
1547a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                    mAsecMountSet.remove(id);
1548a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                }
1549a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1550a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1551a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
15524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
15533697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
15549ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
15554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int mountSecureContainer(String id, String key, int ownerUid) {
15564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
1557207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1558b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
15594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1560a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        synchronized (mAsecMountSet) {
1561a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            if (mAsecMountSet.contains(id)) {
1562a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageMounted;
1563a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1564a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1565a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1566b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
15674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1568dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("asec", "mount", id, key, ownerUid);
15694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1570f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            int code = e.getCode();
1571f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            if (code != VoldResponseCode.OpFailedStorageBusy) {
1572f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root                rc = StorageResultCode.OperationFailedInternalError;
1573f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            }
157402735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
15756cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
15766cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        if (rc == StorageResultCode.OperationSucceeded) {
15776cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            synchronized (mAsecMountSet) {
15786cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat                mAsecMountSet.add(id);
15796cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
15806cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
15814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
15823697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
15833697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1584d970998b0d489774ad1c5b94b47d233912f00214San Mehat    public int unmountSecureContainer(String id, boolean force) {
15854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
1586207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1587b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
15884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
15896cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        synchronized (mAsecMountSet) {
15906cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            if (!mAsecMountSet.contains(id)) {
1591a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageNotMounted;
15926cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
15936cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat         }
15946cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
1595aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
1596aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
1597aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
1598aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
1599aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
1600aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
1601aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
1602aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
1603b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
16044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1605dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            final Command cmd = new Command("asec", "unmount", id);
1606dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            if (force) {
1607dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                cmd.appendArg("force");
1608dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            }
1609dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute(cmd);
16104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1611d970998b0d489774ad1c5b94b47d233912f00214San Mehat            int code = e.getCode();
1612d970998b0d489774ad1c5b94b47d233912f00214San Mehat            if (code == VoldResponseCode.OpFailedStorageBusy) {
1613d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedStorageBusy;
1614d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else {
1615d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedInternalError;
1616d970998b0d489774ad1c5b94b47d233912f00214San Mehat            }
161702735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
16186cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
16196cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        if (rc == StorageResultCode.OperationSucceeded) {
16206cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            synchronized (mAsecMountSet) {
16216cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat                mAsecMountSet.remove(id);
16226cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
16236cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
16244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
16259dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat    }
16269dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat
16276cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    public boolean isSecureContainerMounted(String id) {
16286cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
16296cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        waitForReady();
16306cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        warnOnNotMounted();
16316cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
16326cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        synchronized (mAsecMountSet) {
16336cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            return mAsecMountSet.contains(id);
16346cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
16356cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    }
16366cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
16374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int renameSecureContainer(String oldId, String newId) {
16384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_RENAME);
1639207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1640b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
16414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1642a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        synchronized (mAsecMountSet) {
164385451ee15fdf6cae371dc3005441988c7d426401San Mehat            /*
16449ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks             * Because a mounted container has active internal state which cannot be
164585451ee15fdf6cae371dc3005441988c7d426401San Mehat             * changed while active, we must ensure both ids are not currently mounted.
164685451ee15fdf6cae371dc3005441988c7d426401San Mehat             */
164785451ee15fdf6cae371dc3005441988c7d426401San Mehat            if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
1648a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageMounted;
1649a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1650a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1651a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1652b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
16534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1654dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("asec", "rename", oldId, newId);
16554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1656b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
165702735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1658a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
16594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
166045f61040823d8c442838f75cde8760f236603daeSan Mehat    }
166145f61040823d8c442838f75cde8760f236603daeSan Mehat
16624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String getSecureContainerPath(String id) {
16634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
1664207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1665b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1666f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
1667dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
16682d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        try {
1669dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("asec", "path", id);
1670dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event.checkCode(VoldResponseCode.AsecPathResult);
1671dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return event.getMessage();
16722d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        } catch (NativeDaemonConnectorException e) {
16732d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            int code = e.getCode();
16742d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            if (code == VoldResponseCode.OpFailedStorageNotFound) {
1675a20c8ef471666cf8b0dca91a8739ff18af1741a5Fredrik Helmer                Slog.i(TAG, String.format("Container '%s' not found", id));
1676a20c8ef471666cf8b0dca91a8739ff18af1741a5Fredrik Helmer                return null;
167722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            } else {
16782d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat                throw new IllegalStateException(String.format("Unexpected response code %d", code));
167922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            }
168022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
168122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
1682292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn
1683292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn    public String getSecureContainerFilesystemPath(String id) {
1684292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        validatePermission(android.Manifest.permission.ASEC_ACCESS);
1685292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        waitForReady();
1686292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        warnOnNotMounted();
1687292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn
1688dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
1689292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        try {
1690dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("asec", "fspath", id);
1691dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event.checkCode(VoldResponseCode.AsecPathResult);
1692dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return event.getMessage();
1693292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        } catch (NativeDaemonConnectorException e) {
1694292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn            int code = e.getCode();
1695292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn            if (code == VoldResponseCode.OpFailedStorageNotFound) {
1696292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn                Slog.i(TAG, String.format("Container '%s' not found", id));
1697292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn                return null;
1698292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn            } else {
1699292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn                throw new IllegalStateException(String.format("Unexpected response code %d", code));
1700292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn            }
1701292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        }
1702292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn    }
1703e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu
1704e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu    public void finishMediaUpdate() {
1705e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
1706e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu    }
170702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1708a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
1709a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        if (callerUid == android.os.Process.SYSTEM_UID) {
1710a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return true;
1711a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1712a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
171302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        if (packageName == null) {
171402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            return false;
171502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
171602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1717f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        final int packageUid = mPms.getPackageUid(packageName, UserHandle.getUserId(callerUid));
171802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
171902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        if (DEBUG_OBB) {
172002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
172102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root                    packageUid + ", callerUid = " + callerUid);
172202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
172302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
172402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        return callerUid == packageUid;
172502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
172602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
172702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    public String getMountedObbPath(String filename) {
1728af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (filename == null) {
1729af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("filename cannot be null");
1730af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        }
1731af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
173202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        waitForReady();
173302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        warnOnNotMounted();
173402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1735dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
173602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        try {
1737dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("obb", "path", filename);
1738dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event.checkCode(VoldResponseCode.AsecPathResult);
1739dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return event.getMessage();
174002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        } catch (NativeDaemonConnectorException e) {
174102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            int code = e.getCode();
174202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            if (code == VoldResponseCode.OpFailedStorageNotFound) {
1743a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                return null;
174402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            } else {
174502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root                throw new IllegalStateException(String.format("Unexpected response code %d", code));
174602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
174702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
174802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
174902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
175002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    public boolean isObbMounted(String filename) {
1751af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (filename == null) {
1752af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("filename cannot be null");
1753af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        }
1754af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1755a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        synchronized (mObbMounts) {
1756af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            return mObbPathToStateMap.containsKey(filename);
1757a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1758a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
1759a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1760af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    public void mountObb(String filename, String key, IObbActionListener token, int nonce)
1761735de3b38abbd6564082a819377673ee593744a6Kenny Root            throws RemoteException {
1762f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root        if (filename == null) {
1763f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root            throw new IllegalArgumentException("filename cannot be null");
1764f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root        }
1765f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root
1766af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (token == null) {
1767af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("token cannot be null");
17682942391801b79816c5eb77d7ac94c4a65f26af48Kenny Root        }
1769735de3b38abbd6564082a819377673ee593744a6Kenny Root
1770af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final int callerUid = Binder.getCallingUid();
1771af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final ObbState obbState = new ObbState(filename, callerUid, token, nonce);
1772af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final ObbAction action = new MountObbAction(obbState, key);
1773a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
1774a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1775a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        if (DEBUG_OBB)
1776a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            Slog.i(TAG, "Send to OBB handler: " + action.toString());
177702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
177802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1779af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    public void unmountObb(String filename, boolean force, IObbActionListener token, int nonce)
1780af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throws RemoteException {
1781f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root        if (filename == null) {
1782f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root            throw new IllegalArgumentException("filename cannot be null");
1783f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root        }
1784f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root
1785af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final int callerUid = Binder.getCallingUid();
1786af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final ObbState obbState = new ObbState(filename, callerUid, token, nonce);
1787af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final ObbAction action = new UnmountObbAction(obbState, force);
1788a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
1789a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1790a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        if (DEBUG_OBB)
1791a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            Slog.i(TAG, "Send to OBB handler: " + action.toString());
1792a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
179302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1794444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo    @Override
1795444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo    public int getEncryptionState() {
1796444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
1797444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo                "no permission to access the crypt keeper");
1798444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo
1799444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        waitForReady();
1800444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo
1801dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
1802444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        try {
1803dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("cryptfs", "cryptocomplete");
1804dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return Integer.parseInt(event.getMessage());
1805444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        } catch (NumberFormatException e) {
1806444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            // Bad result - unexpected.
1807444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
1808444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            return ENCRYPTION_STATE_ERROR_UNKNOWN;
1809444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        } catch (NativeDaemonConnectorException e) {
1810444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            // Something bad happened.
1811444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            Slog.w(TAG, "Error in communicating with cryptfs in validating");
1812444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            return ENCRYPTION_STATE_ERROR_UNKNOWN;
1813444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        }
1814444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo    }
1815444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo
1816444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo    @Override
18175af0b916f850486cff4797355bf9e7dc3352fe00Jason parks    public int decryptStorage(String password) {
1818f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (TextUtils.isEmpty(password)) {
1819f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            throw new IllegalArgumentException("password cannot be empty");
18205af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        }
18215af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
18228888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
18238888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks                "no permission to access the crypt keeper");
18245af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
18255af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        waitForReady();
18265af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
18275af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        if (DEBUG_EVENTS) {
18285af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            Slog.i(TAG, "decrypting storage...");
18295af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        }
18305af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
1831dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
18325af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        try {
1833dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("cryptfs", "checkpw", password);
18349ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
1835da6aedf716bfdd40148823fb63d666d34b7b425eFredrik Roubert            final int code = Integer.parseInt(event.getMessage());
18369ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            if (code == 0) {
18379ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                // Decrypt was successful. Post a delayed message before restarting in order
18389ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                // to let the UI to clear itself
18399ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                mHandler.postDelayed(new Runnable() {
18409ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                    public void run() {
184131c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey                        try {
1842dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                            mConnector.execute("cryptfs", "restart");
184331c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey                        } catch (NativeDaemonConnectorException e) {
184431c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey                            Slog.e(TAG, "problem executing in background", e);
184531c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey                        }
18469ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                    }
1847f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks                }, 1000); // 1 second
18489ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            }
18499ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
18509ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            return code;
18515af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        } catch (NativeDaemonConnectorException e) {
18525af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            // Decryption failed
18535af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            return e.getCode();
18545af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        }
18555af0b916f850486cff4797355bf9e7dc3352fe00Jason parks    }
18565af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
185756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks    public int encryptStorage(String password) {
1858f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (TextUtils.isEmpty(password)) {
1859f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            throw new IllegalArgumentException("password cannot be empty");
186056aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        }
186156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
18628888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
18638888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks            "no permission to access the crypt keeper");
186456aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
186556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        waitForReady();
186656aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
186756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        if (DEBUG_EVENTS) {
18688888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks            Slog.i(TAG, "encrypting storage...");
186956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        }
187056aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
187156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        try {
1872dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("cryptfs", "enablecrypto", "inplace", password);
187356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        } catch (NativeDaemonConnectorException e) {
187456aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks            // Encryption failed
187556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks            return e.getCode();
187656aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        }
187756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
187856aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        return 0;
187956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks    }
188056aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
1881f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks    public int changeEncryptionPassword(String password) {
1882f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (TextUtils.isEmpty(password)) {
1883f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            throw new IllegalArgumentException("password cannot be empty");
1884f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        }
1885f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1886f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
1887f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            "no permission to access the crypt keeper");
1888f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1889f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        waitForReady();
1890f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1891f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (DEBUG_EVENTS) {
1892f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            Slog.i(TAG, "changing encryption password...");
1893f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        }
1894f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1895dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
1896f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        try {
1897dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("cryptfs", "changepw", password);
1898dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return Integer.parseInt(event.getMessage());
1899f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        } catch (NativeDaemonConnectorException e) {
1900f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            // Encryption failed
1901f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            return e.getCode();
1902f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        }
1903f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks    }
1904f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
190532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate    /**
190632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate     * Validate a user-supplied password string with cryptfs
190732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate     */
190832418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate    @Override
190932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate    public int verifyEncryptionPassword(String password) throws RemoteException {
191032418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        // Only the system process is permitted to validate passwords
191132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
191232418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            throw new SecurityException("no permission to access the crypt keeper");
191332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        }
191432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
191532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
191632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            "no permission to access the crypt keeper");
191732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
191832418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        if (TextUtils.isEmpty(password)) {
191932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            throw new IllegalArgumentException("password cannot be empty");
192032418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        }
192132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
192232418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        waitForReady();
192332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
192432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        if (DEBUG_EVENTS) {
192532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            Slog.i(TAG, "validating encryption password...");
192632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        }
192732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
1928dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
192932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        try {
1930dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("cryptfs", "verifypw", password);
1931dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
1932dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return Integer.parseInt(event.getMessage());
193332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        } catch (NativeDaemonConnectorException e) {
193432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            // Encryption failed
193532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            return e.getCode();
193632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        }
193732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate    }
193832418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
19392f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    public Parcelable[] getVolumeList() {
19402f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        synchronized(mVolumes) {
19412f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            int size = mVolumes.size();
19422f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            Parcelable[] result = new Parcelable[size];
19432f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            for (int i = 0; i < size; i++) {
19442f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                result[i] = mVolumes.get(i);
19458fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood            }
19468fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood            return result;
19478fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood        }
19488fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood    }
19498fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood
1950af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private void addObbStateLocked(ObbState obbState) throws RemoteException {
1951af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IBinder binder = obbState.getBinder();
1952af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        List<ObbState> obbStates = mObbMounts.get(binder);
19535919ac6b4188285324646772501ef4b97b353cf4Kenny Root
1954af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (obbStates == null) {
1955af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbStates = new ArrayList<ObbState>();
1956af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            mObbMounts.put(binder, obbStates);
1957af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        } else {
1958af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            for (final ObbState o : obbStates) {
1959af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (o.filename.equals(obbState.filename)) {
1960af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    throw new IllegalStateException("Attempt to add ObbState twice. "
1961af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            + "This indicates an error in the MountService logic.");
19625919ac6b4188285324646772501ef4b97b353cf4Kenny Root                }
19635919ac6b4188285324646772501ef4b97b353cf4Kenny Root            }
196402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
196502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1966af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        obbStates.add(obbState);
1967af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        try {
1968af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbState.link();
1969af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        } catch (RemoteException e) {
1970af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            /*
1971af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * The binder died before we could link it, so clean up our state
1972af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * and return failure.
1973af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             */
1974af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbStates.remove(obbState);
1975af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.isEmpty()) {
1976af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mObbMounts.remove(binder);
197705105f7abe02b2dff91d6260b3628c8b97816babKenny Root            }
19785919ac6b4188285324646772501ef4b97b353cf4Kenny Root
1979af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            // Rethrow the error so mountObb can get it
1980af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw e;
198102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
1982af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1983af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        mObbPathToStateMap.put(obbState.filename, obbState);
1984a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
198502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1986af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private void removeObbStateLocked(ObbState obbState) {
1987af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IBinder binder = obbState.getBinder();
1988af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final List<ObbState> obbStates = mObbMounts.get(binder);
1989af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (obbStates != null) {
1990af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.remove(obbState)) {
1991af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                obbState.unlink();
1992af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
1993af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.isEmpty()) {
1994af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mObbMounts.remove(binder);
1995af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
199638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
1997af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1998af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        mObbPathToStateMap.remove(obbState.filename);
199938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    }
200038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2001a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private class ObbActionHandler extends Handler {
2002a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private boolean mBound = false;
2003480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root        private final List<ObbAction> mActions = new LinkedList<ObbAction>();
2004a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2005a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbActionHandler(Looper l) {
2006a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(l);
2007a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2008a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2009a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
2010a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleMessage(Message msg) {
2011a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            switch (msg.what) {
2012a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_RUN_ACTION: {
2013480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                    final ObbAction action = (ObbAction) msg.obj;
2014a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2015a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
2016a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
2017a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2018a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // If a bind was already initiated we don't really
2019a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // need to do anything. The pending install
2020a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // will be processed later on.
2021a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (!mBound) {
2022a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // If this is the only one pending we might
2023a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // have to bind to the service again.
2024a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (!connectToService()) {
2025a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            Slog.e(TAG, "Failed to bind to media container service");
2026a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.handleError();
2027a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            return;
2028a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2029a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2030735de3b38abbd6564082a819377673ee593744a6Kenny Root
2031735de3b38abbd6564082a819377673ee593744a6Kenny Root                    mActions.add(action);
2032a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
2033a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2034a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_BOUND: {
2035a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
2036a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_BOUND");
2037a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (msg.obj != null) {
2038a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mContainerService = (IMediaContainerService) msg.obj;
2039a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2040a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mContainerService == null) {
2041a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Something seriously wrong. Bail out
2042a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.e(TAG, "Cannot bind to media container service");
2043a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        for (ObbAction action : mActions) {
2044a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            // Indicate service bind error
2045a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.handleError();
2046a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2047a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mActions.clear();
2048a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else if (mActions.size() > 0) {
2049480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                        final ObbAction action = mActions.get(0);
2050a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (action != null) {
2051a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.execute(this);
2052a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2053a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else {
2054a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Should never happen ideally.
2055a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.w(TAG, "Empty queue");
2056a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2057a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
2058a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2059a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_RECONNECT: {
2060a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
2061a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_RECONNECT");
2062a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() > 0) {
2063a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (mBound) {
2064a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            disconnectService();
2065a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2066a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (!connectToService()) {
2067a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            Slog.e(TAG, "Failed to bind to media container service");
2068a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            for (ObbAction action : mActions) {
2069a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                                // Indicate service bind error
2070a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                                action.handleError();
2071a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            }
2072a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            mActions.clear();
2073a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2074a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2075a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
2076a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2077a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_UNBIND: {
2078a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
2079a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_UNBIND");
2080a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2081a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // Delete pending install
2082a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() > 0) {
2083a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mActions.remove(0);
2084a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2085a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() == 0) {
2086a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (mBound) {
2087a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            disconnectService();
2088a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2089a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else {
2090a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // There are more pending requests in queue.
2091a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Just post MCS_BOUND message to trigger processing
2092a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // of next pending install.
2093a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
2094a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2095a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
2096a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2097af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                case OBB_FLUSH_MOUNT_STATE: {
2098af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    final String path = (String) msg.obj;
2099af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2100af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    if (DEBUG_OBB)
2101af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        Slog.i(TAG, "Flushing all OBB state for path " + path);
2102af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2103af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    synchronized (mObbMounts) {
2104af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
2105af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2106af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        final Iterator<Entry<String, ObbState>> i =
2107af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                mObbPathToStateMap.entrySet().iterator();
2108af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        while (i.hasNext()) {
2109af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            final Entry<String, ObbState> obbEntry = i.next();
2110af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2111af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            /*
2112af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * If this entry's source file is in the volume path
2113af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * that got unmounted, remove it because it's no
2114af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * longer valid.
2115af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             */
2116af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            if (obbEntry.getKey().startsWith(path)) {
2117af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                obbStatesToRemove.add(obbEntry.getValue());
2118af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            }
2119af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        }
2120af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2121af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        for (final ObbState obbState : obbStatesToRemove) {
2122af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            if (DEBUG_OBB)
2123af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                Slog.i(TAG, "Removing state for " + obbState.filename);
2124af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2125af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            removeObbStateLocked(obbState);
2126af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2127af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            try {
2128af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                obbState.token.onObbResult(obbState.filename, obbState.nonce,
2129af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                        OnObbStateChangeListener.UNMOUNTED);
2130af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            } catch (RemoteException e) {
2131af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                Slog.i(TAG, "Couldn't send unmount notification for  OBB: "
2132af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                        + obbState.filename);
2133af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            }
2134af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        }
2135af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    }
2136af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    break;
2137af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                }
213802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
213902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
214002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2141a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private boolean connectToService() {
2142a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
2143a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "Trying to bind to DefaultContainerService");
2144a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2145a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
2146a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) {
2147a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mBound = true;
2148a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                return true;
214902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
2150a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return false;
2151a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2152a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2153a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private void disconnectService() {
2154a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mContainerService = null;
2155a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mBound = false;
2156a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mContext.unbindService(mDefContainerConn);
215702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
215802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
215902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2160a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    abstract class ObbAction {
2161a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private static final int MAX_RETRIES = 3;
2162a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private int mRetries;
216302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2164a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbState mObbState;
2165a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2166a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbAction(ObbState obbState) {
2167a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbState = obbState;
216802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
216902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2170a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void execute(ObbActionHandler handler) {
2171a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            try {
2172a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
2173444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo                    Slog.i(TAG, "Starting to execute action: " + toString());
2174a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mRetries++;
2175a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (mRetries > MAX_RETRIES) {
2176a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
2177480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                    mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
2178a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    handleError();
2179a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    return;
2180a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                } else {
2181a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    handleExecute();
2182a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
2183a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "Posting install MCS_UNBIND");
2184a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
2185a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2186a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            } catch (RemoteException e) {
2187a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
2188a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.i(TAG, "Posting install MCS_RECONNECT");
2189a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
2190a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            } catch (Exception e) {
2191a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
2192a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.d(TAG, "Error handling OBB action", e);
2193a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                handleError();
219417eb6fb07cc6965f09c51adc70b3c291f57a784aKenny Root                mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
219502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
2196a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
219702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
219805105f7abe02b2dff91d6260b3628c8b97816babKenny Root        abstract void handleExecute() throws RemoteException, IOException;
2199a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        abstract void handleError();
220038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
220138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        protected ObbInfo getObbInfo() throws IOException {
220238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            ObbInfo obbInfo;
220338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            try {
220438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                obbInfo = mContainerService.getObbInfo(mObbState.filename);
220538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } catch (RemoteException e) {
220638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
220738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                        + mObbState.filename);
220838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                obbInfo = null;
220938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
221038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            if (obbInfo == null) {
221138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                throw new IOException("Couldn't read OBB file: " + mObbState.filename);
221238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
221338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return obbInfo;
221438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
221538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2216af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        protected void sendNewStatusOrIgnore(int status) {
2217af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (mObbState == null || mObbState.token == null) {
2218af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2219af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2220af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
222138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            try {
2222af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mObbState.token.onObbResult(mObbState.filename, mObbState.nonce, status);
222338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } catch (RemoteException e) {
222438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
222538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
222638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
2227a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
2228a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2229a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class MountObbAction extends ObbAction {
2230444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        private final String mKey;
2231a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2232a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        MountObbAction(ObbState obbState, String key) {
2233a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(obbState);
2234a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mKey = key;
2235a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2236a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
22375af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
2238735de3b38abbd6564082a819377673ee593744a6Kenny Root        public void handleExecute() throws IOException, RemoteException {
2239af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            waitForReady();
2240af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            warnOnNotMounted();
2241af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
224238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            final ObbInfo obbInfo = getObbInfo();
224338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2244af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mObbState.callerUid)) {
2245af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
2246af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        + " which is owned by " + obbInfo.packageName);
2247af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
2248af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2249af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2250af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2251af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final boolean isMounted;
2252af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            synchronized (mObbMounts) {
2253af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                isMounted = mObbPathToStateMap.containsKey(obbInfo.filename);
2254af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2255af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (isMounted) {
2256af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
2257af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
2258af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2259af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2260af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
226138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            /*
2262af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * The filename passed in might not be the canonical name, so just
2263af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * set the filename to the canonicalized version.
226438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root             */
2265af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            mObbState.filename = obbInfo.filename;
226638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2267af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final String hashedKey;
2268af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (mKey == null) {
2269af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                hashedKey = "none";
2270af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } else {
2271af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                try {
22723b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
22733b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
22743b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
22753b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                            PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
22763b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    SecretKey key = factory.generateSecret(ks);
22773b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    BigInteger bi = new BigInteger(key.getEncoded());
22783b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    hashedKey = bi.toString(16);
2279af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } catch (NoSuchAlgorithmException e) {
22803b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
22813b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
22823b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    return;
22833b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                } catch (InvalidKeySpecException e) {
22843b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
22853b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
2286af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    return;
228738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                }
2288a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
2289a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2290af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            int rc = StorageResultCode.OperationSucceeded;
2291af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            try {
2292dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                mConnector.execute(
2293dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                        "obb", "mount", mObbState.filename, hashedKey, mObbState.callerUid);
2294af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } catch (NativeDaemonConnectorException e) {
2295af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                int code = e.getCode();
2296af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (code != VoldResponseCode.OpFailedStorageBusy) {
2297af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedInternalError;
2298a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2299af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2300a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2301af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (rc == StorageResultCode.OperationSucceeded) {
2302af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (DEBUG_OBB)
2303af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    Slog.d(TAG, "Successfully mounted OBB " + mObbState.filename);
230438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2305af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                synchronized (mObbMounts) {
2306af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    addObbStateLocked(mObbState);
2307a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
230838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2309af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
231002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            } else {
231105105f7abe02b2dff91d6260b3628c8b97816babKenny Root                Slog.e(TAG, "Couldn't mount OBB file: " + rc);
2312a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2313af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
231402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
231502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
231602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
23175af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
2318a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleError() {
2319af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
232002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
2321a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2322a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
2323a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public String toString() {
2324a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            StringBuilder sb = new StringBuilder();
2325a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("MountObbAction{");
2326a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("filename=");
2327a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.filename);
2328a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",callerUid=");
2329a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.callerUid);
2330a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",token=");
2331a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.token != null ? mObbState.token.toString() : "NULL");
2332af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sb.append(",binder=");
2333af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sb.append(mObbState.token != null ? mObbState.getBinder().toString() : "null");
2334a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append('}');
2335a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return sb.toString();
2336a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2337a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
2338a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2339a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class UnmountObbAction extends ObbAction {
2340444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        private final boolean mForceUnmount;
2341a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2342a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        UnmountObbAction(ObbState obbState, boolean force) {
2343a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(obbState);
2344a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mForceUnmount = force;
2345a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2346a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
23475af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
234838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        public void handleExecute() throws IOException {
2349af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            waitForReady();
2350af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            warnOnNotMounted();
2351af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
235238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            final ObbInfo obbInfo = getObbInfo();
2353a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2354af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final ObbState obbState;
235538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            synchronized (mObbMounts) {
2356af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                obbState = mObbPathToStateMap.get(obbInfo.filename);
2357af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
235838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2359af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbState == null) {
2360af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
2361af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2362a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
2363a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2364af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbState.callerUid != mObbState.callerUid) {
2365af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Permission denied attempting to unmount OBB " + obbInfo.filename
2366af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        + " (owned by " + obbInfo.packageName + ")");
2367af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
2368af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2369af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2370a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2371af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            mObbState.filename = obbInfo.filename;
237238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2373af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            int rc = StorageResultCode.OperationSucceeded;
2374af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            try {
2375dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                final Command cmd = new Command("obb", "unmount", mObbState.filename);
2376dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                if (mForceUnmount) {
2377dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                    cmd.appendArg("force");
2378dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                }
2379dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                mConnector.execute(cmd);
2380af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } catch (NativeDaemonConnectorException e) {
2381af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                int code = e.getCode();
2382af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (code == VoldResponseCode.OpFailedStorageBusy) {
2383af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedStorageBusy;
2384af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
2385af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    // If it's not mounted then we've already won.
2386af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationSucceeded;
2387af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } else {
2388af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedInternalError;
2389a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2390a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
239138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2392af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (rc == StorageResultCode.OperationSucceeded) {
2393af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                synchronized (mObbMounts) {
2394af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    removeObbStateLocked(obbState);
2395af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                }
239638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2397af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
239838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } else {
2399af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Could not mount OBB: " + mObbState.filename);
2400af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
240138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
2402a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2403a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
24045af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
2405a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleError() {
2406af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
2407a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2408a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2409a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
2410a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public String toString() {
2411a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            StringBuilder sb = new StringBuilder();
2412a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("UnmountObbAction{");
2413a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("filename=");
2414a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.filename != null ? mObbState.filename : "null");
2415a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",force=");
2416a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mForceUnmount);
2417a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",callerUid=");
2418a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.callerUid);
2419a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",token=");
2420a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.token != null ? mObbState.token.toString() : "null");
2421735de3b38abbd6564082a819377673ee593744a6Kenny Root            sb.append(",binder=");
2422af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sb.append(mObbState.token != null ? mObbState.getBinder().toString() : "null");
2423a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append('}');
2424a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return sb.toString();
2425a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
242602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
242738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
242838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    @Override
242938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
243038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
243138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            pw.println("Permission Denial: can't dump ActivityManager from from pid="
243238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
243338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                    + " without permission " + android.Manifest.permission.DUMP);
243438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return;
243538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
243638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
243738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        synchronized (mObbMounts) {
2438af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("  mObbMounts:");
243938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2440af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet().iterator();
2441af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            while (binders.hasNext()) {
2442af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Entry<IBinder, List<ObbState>> e = binders.next();
2443af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print("    Key="); pw.println(e.getKey().toString());
2444af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                final List<ObbState> obbStates = e.getValue();
244538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                for (final ObbState obbState : obbStates) {
2446af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    pw.print("      "); pw.println(obbState.toString());
244738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                }
244838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
2449af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2450af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("");
2451af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("  mObbPathToStateMap:");
2452af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
2453af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            while (maps.hasNext()) {
2454af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                final Entry<String, ObbState> e = maps.next();
2455af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print("    "); pw.print(e.getKey());
2456af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print(" -> "); pw.println(e.getValue().toString());
2457af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
245838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
24594161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root
24604161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root        pw.println("");
24614161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root
24624161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root        synchronized (mVolumes) {
24634161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root            pw.println("  mVolumes:");
24644161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root
24654161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root            final int N = mVolumes.size();
24664161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root            for (int i = 0; i < N; i++) {
24674161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root                final StorageVolume v = mVolumes.get(i);
24684161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root                pw.print("    ");
24694161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root                pw.println(v.toString());
24704161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root            }
24714161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root        }
2472470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt
2473470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt        pw.println();
2474470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt        pw.println("  mConnection:");
2475470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt        mConnector.dump(fd, pw, args);
247638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    }
24779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2478fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey    /** {@inheritDoc} */
2479fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey    public void monitor() {
2480fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey        if (mConnector != null) {
2481fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey            mConnector.monitor();
2482fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey        }
2483fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey    }
2484fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey}
2485