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
19b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport static android.content.pm.PackageManager.PERMISSION_GRANTED;
20c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
218888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parksimport android.Manifest;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
23a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ComponentName;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
27a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ServiceConnection;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
29b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport android.content.pm.UserInfo;
3002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.content.res.ObbInfo;
312f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.Resources;
322f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.TypedArray;
332f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.content.res.XmlResourceParser;
34ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwoodimport android.hardware.usb.UsbManager;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri;
3602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.os.Binder;
37a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.Environment;
38b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport android.os.Environment.UserEnvironment;
39c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Handler;
405f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.HandlerThread;
41a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.IBinder;
425f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.Looper;
43c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Message;
444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehatimport android.os.RemoteException;
45fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapuimport android.os.ServiceManager;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties;
47f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport android.os.UserHandle;
48a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountService;
49a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountServiceListener;
50a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountShutdownObserver;
51a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IObbActionListener;
52af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Rootimport android.os.storage.OnObbStateChangeListener;
53a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.StorageResultCode;
542f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.os.storage.StorageVolume;
55f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parksimport android.text.TextUtils;
562f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.util.AttributeSet;
57a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehatimport android.util.Slog;
582f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport android.util.Xml;
592f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
60b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.internal.app.IMediaContainerService;
614fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkeyimport com.android.internal.util.Preconditions;
62b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.internal.util.XmlUtils;
63b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.server.NativeDaemonConnector.Command;
64b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.server.am.ActivityManagerService;
65b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.server.pm.PackageManagerService;
66b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.server.pm.UserManagerService;
67b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.google.android.collect.Lists;
68b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.google.android.collect.Maps;
69b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
702f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport org.xmlpull.v1.XmlPullParserException;
71a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
72b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport java.io.File;
7338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.FileDescriptor;
7405105f7abe02b2dff91d6260b3628c8b97816babKenny Rootimport java.io.IOException;
7538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.PrintWriter;
763b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.math.BigInteger;
77735de3b38abbd6564082a819377673ee593744a6Kenny Rootimport java.security.NoSuchAlgorithmException;
783b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.InvalidKeySpecException;
793b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.KeySpec;
8022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehatimport java.util.ArrayList;
81a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.HashMap;
826cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehatimport java.util.HashSet;
8338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Iterator;
84a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.LinkedList;
85a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.List;
86a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.Map;
8738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Map.Entry;
8851a573c76737733638c475f52e441c814e6645ccKenny Rootimport java.util.concurrent.CountDownLatch;
8951a573c76737733638c475f52e441c814e6645ccKenny Rootimport java.util.concurrent.TimeUnit;
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
913b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKey;
923b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKeyFactory;
933b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.spec.PBEKeySpec;
943b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
96b104340496e3a531e26c8f428c808eca0e039f50San Mehat * MountService implements back-end services for platform storage
97b104340496e3a531e26c8f428c808eca0e039f50San Mehat * management.
98b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @hide - Applications should use android.os.storage.StorageManager
99b104340496e3a531e26c8f428c808eca0e039f50San Mehat * to access the MountService.
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
101fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkeyclass MountService extends IMountService.Stub
102fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey        implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
1035af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
104b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    // TODO: listen for user creation/deletion
105b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
106b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private static final boolean LOCAL_LOGD = true;
107b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private static final boolean DEBUG_UNMOUNT = true;
108b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private static final boolean DEBUG_EVENTS = true;
109b7db2726e91f1d9480359d0f83b9cb7769906b34Kenny Root    private static final boolean DEBUG_OBB = false;
11002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
11107714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root    // Disable this since it messes up long-running cryptfs operations.
11207714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root    private static final boolean WATCHDOG_ENABLE = false;
11307714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "MountService";
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
116305bcbf0c961840c4505770d084a1caacc074dbbKenny Root    private static final String VOLD_TAG = "VoldConnector";
117305bcbf0c961840c4505770d084a1caacc074dbbKenny Root
118cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root    /** Maximum number of ASEC containers allowed to be mounted. */
119cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root    private static final int MAX_CONTAINERS = 250;
120cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root
1214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    /*
1224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Internal vold volume state constants
1234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     */
1247fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    class VolumeState {
1257fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Init       = -1;
1267fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int NoMedia    = 0;
1277fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Idle       = 1;
1287fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Pending    = 2;
1297fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Checking   = 3;
1307fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Mounted    = 4;
1317fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Unmounting = 5;
1327fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Formatting = 6;
1337fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Shared     = 7;
1347fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int SharedMnt  = 8;
1357fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
1367fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
1374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    /*
1384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Internal vold response code constants
1394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     */
14022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    class VoldResponseCode {
1414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 100 series - Requestion action was initiated; expect another reply
1434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         *              before proceeding with a new command.
1444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
14522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeListResult               = 110;
14622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int AsecListResult                 = 111;
147c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        public static final int StorageUsersListResult         = 112;
14822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
1494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 200 series - Requestion action has been successfully completed.
1514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
1524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int ShareStatusResult              = 210;
15322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int AsecPathResult                 = 211;
1544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int ShareEnabledResult             = 212;
15522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
1564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 400 series - Command was accepted, but the requested action
1584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         *              did not take place.
1594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
1604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedNoMedia                = 401;
1614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedMediaBlank             = 402;
1624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedMediaCorrupt           = 403;
1634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedVolNotMounted          = 404;
164d970998b0d489774ad1c5b94b47d233912f00214San Mehat        public static final int OpFailedStorageBusy            = 405;
1652d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        public static final int OpFailedStorageNotFound        = 406;
1664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 600 series - Unsolicited broadcasts.
1694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
17022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeStateChange              = 605;
17122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeDiskInserted             = 630;
17222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeDiskRemoved              = 631;
17322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeBadRemoval               = 632;
17422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
17522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
176b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private Context mContext;
177b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private NativeDaemonConnector mConnector;
178b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
179b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private final Object mVolumesLock = new Object();
180b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
181b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    /** When defined, base template for user-specific {@link StorageVolume}. */
182b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private StorageVolume mEmulatedTemplate;
183b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
184b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    // @GuardedBy("mVolumesLock")
185b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private final ArrayList<StorageVolume> mVolumes = Lists.newArrayList();
186b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    /** Map from path to {@link StorageVolume} */
187b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    // @GuardedBy("mVolumesLock")
188b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private final HashMap<String, StorageVolume> mVolumesByPath = Maps.newHashMap();
189b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    /** Map from path to state */
190b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    // @GuardedBy("mVolumesLock")
191b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private final HashMap<String, String> mVolumeStates = Maps.newHashMap();
192b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
193b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private volatile boolean mSystemReady = false;
194b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private PackageManagerService                 mPms;
1964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private boolean                               mUmsEnabling;
197ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood    private boolean                               mUmsAvailable = false;
1980eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    // Used as a lock for methods that register/unregister listeners.
1990eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    final private ArrayList<MountServiceBinderListener> mListeners =
2000eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            new ArrayList<MountServiceBinderListener>();
20151a573c76737733638c475f52e441c814e6645ccKenny Root    private CountDownLatch                        mConnectedSignal = new CountDownLatch(1);
20251a573c76737733638c475f52e441c814e6645ccKenny Root    private CountDownLatch                        mAsecsScanned = new CountDownLatch(1);
2036a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private boolean                               mSendUmsConnectedOnBoot = false;
204fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapu
2056cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    /**
2066cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat     * Private hash of currently mounted secure containers.
2070eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu     * Used as a lock in methods to manipulate secure containers.
2086cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat     */
2090eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    final private HashSet<String> mAsecMountSet = new HashSet<String>();
2106cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
21102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    /**
2123b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * The size of the crypto algorithm key in bits for OBB files. Currently
2133b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * Twofish is used which takes 128-bit keys.
2143b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     */
2153b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
2163b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
2173b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    /**
2183b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * The number of times to run SHA1 in the PBKDF2 function for OBB files.
2193b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * 1024 is reasonably secure and not too slow.
2203b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     */
2213b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    private static final int PBKDF2_HASH_ROUNDS = 1024;
2223b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
2233b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    /**
224a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * Mounted OBB tracking information. Used to track the current state of all
225a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * OBBs.
226a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     */
227735de3b38abbd6564082a819377673ee593744a6Kenny Root    final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
2284fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
2294fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    /** Map from raw paths to {@link ObbState}. */
230a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
231a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
232a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class ObbState implements IBinder.DeathRecipient {
2334fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        public ObbState(String rawPath, String canonicalPath, int callingUid,
2344fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                IObbActionListener token, int nonce) {
2354fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            this.rawPath = rawPath;
2364fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            this.canonicalPath = canonicalPath.toString();
2374fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
2384fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            final int userId = UserHandle.getUserId(callingUid);
2394fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            this.ownerPath = buildObbPath(canonicalPath, userId, false);
2404fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            this.voldPath = buildObbPath(canonicalPath, userId, true);
2414fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
2424fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            this.ownerGid = UserHandle.getSharedAppGid(callingUid);
243af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            this.token = token;
244af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            this.nonce = nonce;
245a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
246a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2474fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final String rawPath;
2484fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final String canonicalPath;
2494fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final String ownerPath;
2504fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final String voldPath;
251a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2524fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final int ownerGid;
253a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
254af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        // Token of remote Binder caller
255af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IObbActionListener token;
256af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
257af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        // Identifier to pass back to the token
258af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final int nonce;
259a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
260735de3b38abbd6564082a819377673ee593744a6Kenny Root        public IBinder getBinder() {
261735de3b38abbd6564082a819377673ee593744a6Kenny Root            return token.asBinder();
262735de3b38abbd6564082a819377673ee593744a6Kenny Root        }
263735de3b38abbd6564082a819377673ee593744a6Kenny Root
264a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
265a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void binderDied() {
266a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            ObbAction action = new UnmountObbAction(this, true);
267a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
268735de3b38abbd6564082a819377673ee593744a6Kenny Root        }
269a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2705919ac6b4188285324646772501ef4b97b353cf4Kenny Root        public void link() throws RemoteException {
2715919ac6b4188285324646772501ef4b97b353cf4Kenny Root            getBinder().linkToDeath(this, 0);
2725919ac6b4188285324646772501ef4b97b353cf4Kenny Root        }
2735919ac6b4188285324646772501ef4b97b353cf4Kenny Root
2745919ac6b4188285324646772501ef4b97b353cf4Kenny Root        public void unlink() {
275735de3b38abbd6564082a819377673ee593744a6Kenny Root            getBinder().unlinkToDeath(this, 0);
276a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
27738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
27838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        @Override
27938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        public String toString() {
28038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            StringBuilder sb = new StringBuilder("ObbState{");
2814fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append("rawPath=").append(rawPath);
2824fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append(",canonicalPath=").append(canonicalPath);
2834fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append(",ownerPath=").append(ownerPath);
2844fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append(",voldPath=").append(voldPath);
2854fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append(",ownerGid=").append(ownerGid);
2864fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append(",token=").append(token);
2874fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append(",binder=").append(getBinder());
28838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append('}');
28938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return sb.toString();
29038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
291a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
292a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
293a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // OBB Action Handler
294a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private ObbActionHandler mObbActionHandler;
295a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
296a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // OBB action handler messages
297a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_RUN_ACTION = 1;
298a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_BOUND = 2;
299a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_UNBIND = 3;
300a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_RECONNECT = 4;
301af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private static final int OBB_FLUSH_MOUNT_STATE = 5;
302a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
303a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    /*
304a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * Default Container Service information
30502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root     */
306a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
307a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
308a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
309a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
310a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
311a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class DefaultContainerConnection implements ServiceConnection {
312a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void onServiceConnected(ComponentName name, IBinder service) {
313a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
314a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "onServiceConnected");
315a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
316a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
317a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
318a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
319a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void onServiceDisconnected(ComponentName name) {
320a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
321a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "onServiceDisconnected");
322a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
323a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    };
324a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
325a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // Used in the ObbActionHandler
326a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private IMediaContainerService mContainerService = null;
32702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
32802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    // Handler messages
329c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_PM_UPDATE = 1;
330c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_PM_DONE = 2;
331c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_MS = 3;
332b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private static final int H_SYSTEM_READY = 4;
333b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
334c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int RETRY_UNMOUNT_DELAY = 30; // in ms
335c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int MAX_UNMOUNT_RETRIES = 4;
336c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
337c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    class UnmountCallBack {
33805105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final String path;
33905105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final boolean force;
34013c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo        final boolean removeEncryption;
341c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        int retries;
342c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
34313c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo        UnmountCallBack(String path, boolean force, boolean removeEncryption) {
344c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            retries = 0;
345c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            this.path = path;
346c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            this.force = force;
34713c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            this.removeEncryption = removeEncryption;
348c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        }
3490eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3500eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        void handleFinished() {
351a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path);
35213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            doUnmountVolume(path, true, removeEncryption);
3530eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
3540eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
3550eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3560eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    class UmsEnableCallBack extends UnmountCallBack {
35705105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final String method;
3580eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3590eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        UmsEnableCallBack(String path, String method, boolean force) {
36013c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            super(path, force, false);
3610eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            this.method = method;
3620eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
3630eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3640eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        @Override
3650eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        void handleFinished() {
3660eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            super.handleFinished();
3670eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            doShareUnshareVolume(path, method, true);
3680eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
369c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    }
370c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
3716ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    class ShutdownCallBack extends UnmountCallBack {
3726ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        IMountShutdownObserver observer;
3736ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        ShutdownCallBack(String path, IMountShutdownObserver observer) {
37413c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            super(path, true, false);
3756ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            this.observer = observer;
3766ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        }
3776ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3786ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        @Override
3796ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        void handleFinished() {
38013c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            int ret = doUnmountVolume(path, true, removeEncryption);
3816ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            if (observer != null) {
3826ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                try {
3836ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    observer.onShutDownComplete(ret);
3846ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                } catch (RemoteException e) {
385a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.w(TAG, "RemoteException when shutting down");
3866ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                }
3876ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            }
3886ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        }
3896ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    }
3906ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3915f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler    class MountServiceHandler extends Handler {
392c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>();
393e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        boolean mUpdatingStatus = false;
3946ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3955f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        MountServiceHandler(Looper l) {
3965f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler            super(l);
3975f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        }
3985f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler
3995af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
400c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        public void handleMessage(Message msg) {
401c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            switch (msg.what) {
402c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                case H_UNMOUNT_PM_UPDATE: {
403a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_UPDATE");
404c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    UnmountCallBack ucb = (UnmountCallBack) msg.obj;
405c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    mForceUnmounts.add(ucb);
406a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, " registered = " + mUpdatingStatus);
4076ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    // Register only if needed.
408e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                    if (!mUpdatingStatus) {
409a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        if (DEBUG_UNMOUNT) Slog.i(TAG, "Updating external media status on PackageManager");
410e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                        mUpdatingStatus = true;
411e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                        mPms.updateExternalMediaStatus(false, true);
412c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    }
413c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
414c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
415c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                case H_UNMOUNT_PM_DONE: {
416a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_DONE");
417a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "Updated status. Processing requests");
418e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                    mUpdatingStatus = false;
4196ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int size = mForceUnmounts.size();
4206ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int sizeArr[] = new int[size];
4216ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int sizeArrN = 0;
4227af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    // Kill processes holding references first
4237af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    ActivityManagerService ams = (ActivityManagerService)
4247af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    ServiceManager.getService("activity");
4256ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    for (int i = 0; i < size; i++) {
4266ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        UnmountCallBack ucb = mForceUnmounts.get(i);
4276ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        String path = ucb.path;
4286ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        boolean done = false;
4296ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        if (!ucb.force) {
430c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                            done = true;
431c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        } else {
4326ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            int pids[] = getStorageUsers(path);
4336ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            if (pids == null || pids.length == 0) {
4346ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                                done = true;
4356ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            } else {
4366ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                                // Eliminate system process here?
437648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn                                ams.killPids(pids, "unmount media", true);
4387af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                // Confirm if file references have been freed.
4397af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                pids = getStorageUsers(path);
4407af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                if (pids == null || pids.length == 0) {
4417af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    done = true;
442c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                                }
443c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                            }
444c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        }
4457af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                        if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) {
4467af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            // Retry again
4477af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            Slog.i(TAG, "Retrying to kill storage users again");
4487af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            mHandler.sendMessageDelayed(
4497af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    mHandler.obtainMessage(H_UNMOUNT_PM_DONE,
4507af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                            ucb.retries++),
4517af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    RETRY_UNMOUNT_DELAY);
452c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        } else {
4536ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            if (ucb.retries >= MAX_UNMOUNT_RETRIES) {
4547af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                Slog.i(TAG, "Failed to unmount media inspite of " +
4557af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                        MAX_UNMOUNT_RETRIES + " retries. Forcibly killing processes now");
4566ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            }
4577af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            sizeArr[sizeArrN++] = i;
4587af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS,
4597af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    ucb));
460c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        }
461c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    }
4626ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    // Remove already processed elements from list.
4636ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    for (int i = (sizeArrN-1); i >= 0; i--) {
4646ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        mForceUnmounts.remove(sizeArr[i]);
4656ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    }
466c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
467c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
468b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                case H_UNMOUNT_MS: {
469a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_MS");
470c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    UnmountCallBack ucb = (UnmountCallBack) msg.obj;
4710eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                    ucb.handleFinished();
472c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
473c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
474b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                case H_SYSTEM_READY: {
475b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    try {
476b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        handleSystemReady();
477b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    } catch (Exception ex) {
478b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        Slog.e(TAG, "Boot-time mount exception", ex);
479b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    }
480b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    break;
481b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                }
482c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            }
483c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        }
484c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    };
485b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
486b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private final HandlerThread mHandlerThread;
487b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private final Handler mHandler;
488c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
48951a573c76737733638c475f52e441c814e6645ccKenny Root    void waitForAsecScan() {
49051a573c76737733638c475f52e441c814e6645ccKenny Root        waitForLatch(mAsecsScanned);
49151a573c76737733638c475f52e441c814e6645ccKenny Root    }
49251a573c76737733638c475f52e441c814e6645ccKenny Root
493207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void waitForReady() {
49451a573c76737733638c475f52e441c814e6645ccKenny Root        waitForLatch(mConnectedSignal);
49551a573c76737733638c475f52e441c814e6645ccKenny Root    }
49651a573c76737733638c475f52e441c814e6645ccKenny Root
49751a573c76737733638c475f52e441c814e6645ccKenny Root    private void waitForLatch(CountDownLatch latch) {
49851a573c76737733638c475f52e441c814e6645ccKenny Root        if (latch == null) {
49951a573c76737733638c475f52e441c814e6645ccKenny Root            return;
50051a573c76737733638c475f52e441c814e6645ccKenny Root        }
50151a573c76737733638c475f52e441c814e6645ccKenny Root
50251a573c76737733638c475f52e441c814e6645ccKenny Root        for (;;) {
50351a573c76737733638c475f52e441c814e6645ccKenny Root            try {
50451a573c76737733638c475f52e441c814e6645ccKenny Root                if (latch.await(5000, TimeUnit.MILLISECONDS)) {
505207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    return;
50651a573c76737733638c475f52e441c814e6645ccKenny Root                } else {
50751a573c76737733638c475f52e441c814e6645ccKenny Root                    Slog.w(TAG, "Thread " + Thread.currentThread().getName()
50851a573c76737733638c475f52e441c814e6645ccKenny Root                            + " still waiting for MountService ready...");
509207e538350665cea00e1aa70b8094beca4a34e45San Mehat                }
51051a573c76737733638c475f52e441c814e6645ccKenny Root            } catch (InterruptedException e) {
51151a573c76737733638c475f52e441c814e6645ccKenny Root                Slog.w(TAG, "Interrupt while waiting for MountService to be ready.");
512207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
513207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
5141f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat    }
51502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
516b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private void handleSystemReady() {
517b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        // Snapshot current volume states since it's not safe to call into vold
518b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        // while holding locks.
519b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final HashMap<String, String> snapshot;
520b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
521b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            snapshot = new HashMap<String, String>(mVolumeStates);
522b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
52391c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
524b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        for (Map.Entry<String, String> entry : snapshot.entrySet()) {
525b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final String path = entry.getKey();
526b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final String state = entry.getValue();
52722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
528b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            if (state.equals(Environment.MEDIA_UNMOUNTED)) {
529b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                int rc = doMountVolume(path);
530b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                if (rc != StorageResultCode.OperationSucceeded) {
531b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    Slog.e(TAG, String.format("Boot-time mount failed (%d)",
532b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            rc));
533b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                }
534b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            } else if (state.equals(Environment.MEDIA_SHARED)) {
535c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                /*
536b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                 * Bootstrap UMS enabled state since vold indicates
537b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                 * the volume is shared (runtime restart while ums enabled)
538c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                 */
539b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                notifyVolumeStateChange(null, path, VolumeState.NoMedia,
540b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        VolumeState.Shared);
541b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            }
542b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
543b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
544b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        // Push mounted state for all emulated storage
545b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
546b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            for (StorageVolume volume : mVolumes) {
547b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                if (volume.isEmulated()) {
548b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED);
549c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                }
550b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            }
551b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
55284338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood
553b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        /*
554b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey         * If UMS was connected on boot, send the connected event
555b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey         * now that we're up.
556b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey         */
557b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (mSendUmsConnectedOnBoot) {
558b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            sendUmsIntent(true);
559b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            mSendUmsConnectedOnBoot = false;
560b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
561b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    }
5626a254403235196692b1769d2fe281b0852c0cc25San Mehat
563b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
564b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        @Override
565b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        public void onReceive(Context context, Intent intent) {
566b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
567b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            if (userId == -1) return;
568b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final UserHandle user = new UserHandle(userId);
569b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
570b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final String action = intent.getAction();
571b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            if (Intent.ACTION_USER_ADDED.equals(action)) {
572b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                synchronized (mVolumesLock) {
573b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    createEmulatedVolumeForUserLocked(user);
574b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                }
575b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
576b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
577b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                synchronized (mVolumesLock) {
578b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    final List<StorageVolume> toRemove = Lists.newArrayList();
579b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    for (StorageVolume volume : mVolumes) {
580b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        if (user.equals(volume.getOwner())) {
581b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            toRemove.add(volume);
582fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                        }
583207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    }
584b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    for (StorageVolume volume : toRemove) {
585b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        removeVolumeLocked(volume);
586b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    }
587b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                }
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
591b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
592b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
593b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        @Override
594b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        public void onReceive(Context context, Intent intent) {
595b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            boolean available = (intent.getBooleanExtra(UsbManager.USB_CONNECTED, false) &&
596b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    intent.getBooleanExtra(UsbManager.USB_FUNCTION_MASS_STORAGE, false));
597b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            notifyShareAvailabilityChange(available);
598b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
599b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    };
600b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
6014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private final class MountServiceBinderListener implements IBinder.DeathRecipient {
6024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        final IMountServiceListener mListener;
60391c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
6044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        MountServiceBinderListener(IMountServiceListener listener) {
6054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mListener = listener;
60602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
60791c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat        }
60891c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
6094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public void binderDied() {
610a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!");
611a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            synchronized (mListeners) {
6124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListeners.remove(this);
6134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListener.asBinder().unlinkToDeath(this, 0);
61491c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat            }
61591c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat        }
61691c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat    }
61791c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
6180eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private void doShareUnshareVolume(String path, String method, boolean enable) {
6194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        // TODO: Add support for multiple share methods
6204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (!method.equals("ums")) {
6214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            throw new IllegalArgumentException(String.format("Method %s not supported", method));
6227fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
625dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("volume", enable ? "share" : "unshare", path, method);
6264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
627a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Failed to share/unshare", e);
62822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
631b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private void updatePublicVolumeState(StorageVolume volume, String state) {
632b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final String path = volume.getPath();
633b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final String oldState;
634b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
6357fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            oldState = mVolumeStates.put(path, state);
6367fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
637b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
6387fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood        if (state.equals(oldState)) {
6397fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            Slog.w(TAG, String.format("Duplicate state transition (%s -> %s) for %s",
6407fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    state, state, path));
641b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return;
642b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
643af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
6447fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood        Slog.d(TAG, "volume state changed for " + path + " (" + oldState + " -> " + state + ")");
6457fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood
646b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        // Tell PackageManager about changes to primary volume state, but only
647b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        // when not emulated.
648b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (volume.isPrimary() && !volume.isEmulated()) {
649b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            if (Environment.MEDIA_UNMOUNTED.equals(state)) {
650b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                mPms.updateExternalMediaStatus(false, false);
6517fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood
652b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                /*
653b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                 * Some OBBs might have been unmounted when this volume was
654b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                 * unmounted, so send a message to the handler to let it know to
655b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                 * remove those from the list of mounted OBBS.
656b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                 */
657b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
658b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        OBB_FLUSH_MOUNT_STATE, path));
659b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            } else if (Environment.MEDIA_MOUNTED.equals(state)) {
660b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                mPms.updateExternalMediaStatus(true, false);
66103559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood            }
6628a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
663b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
6644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
6654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for (int i = mListeners.size() -1; i >= 0; i--) {
6664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                MountServiceBinderListener bl = mListeners.get(i);
6674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                try {
668b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    bl.mListener.onStorageStateChanged(path, oldState, state);
6694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (RemoteException rex) {
670a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener dead");
6714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(i);
6724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (Exception ex) {
673a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener failed", ex);
6744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
67922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    /**
68022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     * Callback from NativeDaemonConnector
68122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     */
68222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    public void onDaemonConnected() {
6835b77dab23469273d41f9c530d947ac055765e6eaSan Mehat        /*
6845b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         * Since we'll be calling back into the NativeDaemonConnector,
6855b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         * we need to do our work in a new thread.
6865b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         */
68751a573c76737733638c475f52e441c814e6645ccKenny Root        new Thread("MountService#onDaemonConnected") {
6885af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            @Override
6897fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            public void run() {
6905b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                /**
6915b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                 * Determine media state and UMS detection status
6925b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                 */
6937fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                try {
694dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                    final String[] vols = NativeDaemonEvent.filterMessageList(
695dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                            mConnector.executeForList("volume", "list"),
696dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                            VoldResponseCode.VolumeListResult);
6975b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                    for (String volstr : vols) {
6985b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        String[] tok = volstr.split(" ");
6995b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        // FMT: <label> <mountpoint> <state>
7007fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        String path = tok[1];
7017fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        String state = Environment.MEDIA_REMOVED;
7027fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood
703b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        final StorageVolume volume;
704b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        synchronized (mVolumesLock) {
705b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            volume = mVolumesByPath.get(path);
706b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        }
707b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
7085b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        int st = Integer.parseInt(tok[2]);
7095b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        if (st == VolumeState.NoMedia) {
7105b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_REMOVED;
7115b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Idle) {
712207e538350665cea00e1aa70b8094beca4a34e45San Mehat                            state = Environment.MEDIA_UNMOUNTED;
7135b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Mounted) {
7145b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_MOUNTED;
715a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.i(TAG, "Media already mounted on daemon connection");
7165b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Shared) {
7175b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_SHARED;
718a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.i(TAG, "Media shared on daemon connection");
7195b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else {
7205b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            throw new Exception(String.format("Unexpected state %d", st));
7217fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                        }
7227fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood
7237fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        if (state != null) {
7247fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                            if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state);
725b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            updatePublicVolumeState(volume, state);
7267fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        }
727c2a39471642e31d7350910612e40d078b825173aSan Mehat                    }
7285b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                } catch (Exception e) {
729a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Error processing initial volume state", e);
730b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    final StorageVolume primary = getPrimaryPhysicalVolume();
731b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    if (primary != null) {
732b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        updatePublicVolumeState(primary, Environment.MEDIA_REMOVED);
733b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    }
7347fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                }
7357fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
736207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
7379ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                 * Now that we've done our initialization, release
738207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * the hounds!
739207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
74051a573c76737733638c475f52e441c814e6645ccKenny Root                mConnectedSignal.countDown();
74151a573c76737733638c475f52e441c814e6645ccKenny Root                mConnectedSignal = null;
74251a573c76737733638c475f52e441c814e6645ccKenny Root
74351a573c76737733638c475f52e441c814e6645ccKenny Root                // Let package manager load internal ASECs.
74451a573c76737733638c475f52e441c814e6645ccKenny Root                mPms.scanAvailableAsecs();
74551a573c76737733638c475f52e441c814e6645ccKenny Root
74651a573c76737733638c475f52e441c814e6645ccKenny Root                // Notify people waiting for ASECs to be scanned that it's done.
74751a573c76737733638c475f52e441c814e6645ccKenny Root                mAsecsScanned.countDown();
74851a573c76737733638c475f52e441c814e6645ccKenny Root                mAsecsScanned = null;
7497fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            }
7507fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }.start();
7517fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
7527fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
75322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    /**
75422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     * Callback from NativeDaemonConnector
75522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     */
75622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    public boolean onEvent(int code, String raw, String[] cooked) {
7578a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        if (DEBUG_EVENTS) {
7588a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            StringBuilder builder = new StringBuilder();
7598a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            builder.append("onEvent::");
7608a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            builder.append(" raw= " + raw);
7618a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            if (cooked != null) {
7628a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                builder.append(" cooked = " );
7638a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                for (String str : cooked) {
7648a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                    builder.append(" " + str);
7658a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                }
7668a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            }
767a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.i(TAG, builder.toString());
7688a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
76922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        if (code == VoldResponseCode.VolumeStateChange) {
7704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            /*
7714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * One of the volumes we're managing has changed state.
7724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * Format: "NNN Volume <label> <path> state changed
7734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * from <old_#> (<old_str>) to <new_#> (<new_str>)"
7744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             */
77522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            notifyVolumeStateChange(
77622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat                    cooked[2], cooked[3], Integer.parseInt(cooked[7]),
77722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat                            Integer.parseInt(cooked[10]));
7784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } else if ((code == VoldResponseCode.VolumeDiskInserted) ||
7794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                   (code == VoldResponseCode.VolumeDiskRemoved) ||
7804270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                   (code == VoldResponseCode.VolumeBadRemoval)) {
78122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
78222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
78322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
784a5250c93928e256738125b265e10c96c3575597eMike Lockwood            String action = null;
7854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            final String label = cooked[2];
7864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            final String path = cooked[3];
7874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            int major = -1;
7884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            int minor = -1;
7894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
7904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            try {
7914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                String devComp = cooked[6].substring(1, cooked[6].length() -1);
7924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                String[] devTok = devComp.split(":");
7934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                major = Integer.parseInt(devTok[0]);
7944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                minor = Integer.parseInt(devTok[1]);
7954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } catch (Exception ex) {
796a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to parse major/minor", ex);
7974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
7984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
799b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final StorageVolume volume;
800b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final String state;
801b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            synchronized (mVolumesLock) {
802b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                volume = mVolumesByPath.get(path);
803b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                state = mVolumeStates.get(path);
804b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            }
805b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
8064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            if (code == VoldResponseCode.VolumeDiskInserted) {
8074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                new Thread() {
8085af0b916f850486cff4797355bf9e7dc3352fe00Jason parks                    @Override
8094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    public void run() {
8104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        try {
8114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                            int rc;
812b104340496e3a531e26c8f428c808eca0e039f50San Mehat                            if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
813a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                                Slog.w(TAG, String.format("Insertion mount failed (%d)", rc));
8144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                            }
8154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        } catch (Exception ex) {
816a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.w(TAG, "Failed to mount media on insertion", ex);
8174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        }
8184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    }
8194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }.start();
8204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else if (code == VoldResponseCode.VolumeDiskRemoved) {
8214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /*
8224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                 * This event gets trumped if we're already in BAD_REMOVAL state
8234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                 */
8244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
8254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    return true;
8264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
8274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /* Send the media unmounted event first */
828a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
829b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);
830b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                sendStorageIntent(Environment.MEDIA_UNMOUNTED, volume, UserHandle.ALL);
8314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
832a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed");
833b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                updatePublicVolumeState(volume, Environment.MEDIA_REMOVED);
834a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_REMOVED;
8354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else if (code == VoldResponseCode.VolumeBadRemoval) {
836a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
8374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /* Send the media unmounted event first */
838b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);
839a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_UNMOUNTED;
8404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
841a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal");
842b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                updatePublicVolumeState(volume, Environment.MEDIA_BAD_REMOVAL);
843a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_BAD_REMOVAL;
8444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else {
845a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Unknown code {%d}", code));
8464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
847a5250c93928e256738125b265e10c96c3575597eMike Lockwood
848a5250c93928e256738125b265e10c96c3575597eMike Lockwood            if (action != null) {
849b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                sendStorageIntent(action, volume, UserHandle.ALL);
850a5250c93928e256738125b265e10c96c3575597eMike Lockwood            }
85122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        } else {
85222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            return false;
85322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
8544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
8555f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        return true;
85622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
85722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
858207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void notifyVolumeStateChange(String label, String path, int oldState, int newState) {
859b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume volume;
860b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final String state;
861b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
862b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            volume = mVolumesByPath.get(path);
863b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            state = getVolumeState(path);
864b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
865b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
866b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChange::" + state);
8674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
868a5250c93928e256738125b265e10c96c3575597eMike Lockwood        String action = null;
8697fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
870bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood        if (oldState == VolumeState.Shared && newState != oldState) {
871a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent");
872b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            sendStorageIntent(Intent.ACTION_MEDIA_UNSHARED, volume, UserHandle.ALL);
873bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood        }
874bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood
8757fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        if (newState == VolumeState.Init) {
8767fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.NoMedia) {
8777fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            // NoMedia is handled via Disk Remove events
8787fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Idle) {
8795fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat            /*
8805fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or
8815fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             * if we're in the process of enabling UMS
8825fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             */
883b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            if (!state.equals(
884b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    Environment.MEDIA_BAD_REMOVAL) && !state.equals(
885b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            Environment.MEDIA_NOFS) && !state.equals(
8860eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                                    Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) {
887a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable");
888b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);
889a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_UNMOUNTED;
8907fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            }
8917fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Pending) {
8927fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Checking) {
893a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking");
894b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            updatePublicVolumeState(volume, Environment.MEDIA_CHECKING);
895a5250c93928e256738125b265e10c96c3575597eMike Lockwood            action = Intent.ACTION_MEDIA_CHECKING;
8967fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Mounted) {
897a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted");
898b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED);
899a5250c93928e256738125b265e10c96c3575597eMike Lockwood            action = Intent.ACTION_MEDIA_MOUNTED;
9007fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Unmounting) {
901a5250c93928e256738125b265e10c96c3575597eMike Lockwood            action = Intent.ACTION_MEDIA_EJECT;
9027fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Formatting) {
9037fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Shared) {
904a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted");
9054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            /* Send the media unmounted event first */
906b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);
907b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL);
9084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
909a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared");
910b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            updatePublicVolumeState(volume, Environment.MEDIA_SHARED);
911a5250c93928e256738125b265e10c96c3575597eMike Lockwood            action = Intent.ACTION_MEDIA_SHARED;
912a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent");
9137fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.SharedMnt) {
914a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Live shared mounts not supported yet!");
9154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            return;
9167fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else {
917a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Unhandled VolumeState {" + newState + "}");
9187fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
9197fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
920a5250c93928e256738125b265e10c96c3575597eMike Lockwood        if (action != null) {
921b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            sendStorageIntent(action, volume, UserHandle.ALL);
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
925207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private int doMountVolume(String path) {
926b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
927207e538350665cea00e1aa70b8094beca4a34e45San Mehat
928b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume volume;
929b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
930b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            volume = mVolumesByPath.get(path);
931b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
932b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
933a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path);
934207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
935dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("volume", "mount", path);
936207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
937207e538350665cea00e1aa70b8094beca4a34e45San Mehat            /*
938207e538350665cea00e1aa70b8094beca4a34e45San Mehat             * Mount failed for some reason
939207e538350665cea00e1aa70b8094beca4a34e45San Mehat             */
940a5250c93928e256738125b265e10c96c3575597eMike Lockwood            String action = null;
941207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
942207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedNoMedia) {
943207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
944207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Attempt to mount but no media inserted
945207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
946b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedNoMedia;
947207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaBlank) {
948a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs");
949207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
950207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Media is blank or does not contain a supported filesystem
951207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
952b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                updatePublicVolumeState(volume, Environment.MEDIA_NOFS);
953a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_NOFS;
954b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedMediaBlank;
955207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
956a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state media corrupt");
957207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
958207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Volume consistency check failed
959207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
960b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTABLE);
961a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_UNMOUNTABLE;
962b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedMediaCorrupt;
963207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
964b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedInternalError;
965207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
966207e538350665cea00e1aa70b8094beca4a34e45San Mehat
967207e538350665cea00e1aa70b8094beca4a34e45San Mehat            /*
968207e538350665cea00e1aa70b8094beca4a34e45San Mehat             * Send broadcast intent (if required for the failure)
969207e538350665cea00e1aa70b8094beca4a34e45San Mehat             */
970a5250c93928e256738125b265e10c96c3575597eMike Lockwood            if (action != null) {
971b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                sendStorageIntent(action, volume, UserHandle.ALL);
972207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
973207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
974207e538350665cea00e1aa70b8094beca4a34e45San Mehat
975207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return rc;
976207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
977207e538350665cea00e1aa70b8094beca4a34e45San Mehat
978c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    /*
979c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * If force is not set, we do not unmount if there are
980c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * processes holding references to the volume about to be unmounted.
981c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * If force is set, all the processes holding references need to be
982c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * killed via the ActivityManager before actually unmounting the volume.
983c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * This might even take a while and might be retried after timed delays
984c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * to make sure we dont end up in an instable state and kill some core
985c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * processes.
98613c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo     * If removeEncryption is set, force is implied, and the system will remove any encryption
98713c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo     * mapping set on the volume when unmounting.
988c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     */
98913c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo    private int doUnmountVolume(String path, boolean force, boolean removeEncryption) {
99059443a673a736978361dc341f41ce4e9dae053a0San Mehat        if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
991207e538350665cea00e1aa70b8094beca4a34e45San Mehat            return VoldResponseCode.OpFailedVolNotMounted;
992207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
993aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
994aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
995aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
996aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
997aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
998aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
999aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
1000aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
1001aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
1002c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        // Redundant probably. But no harm in updating state again.
1003e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        mPms.updateExternalMediaStatus(false, false);
1004207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
1005dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            final Command cmd = new Command("volume", "unmount", path);
1006dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            if (removeEncryption) {
1007dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                cmd.appendArg("force_and_revert");
1008dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            } else if (force) {
1009dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                cmd.appendArg("force");
1010dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            }
1011dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute(cmd);
1012e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            // We unmounted the volume. None of the asec containers are available now.
1013e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            synchronized (mAsecMountSet) {
1014e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                mAsecMountSet.clear();
1015e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            }
1016b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return StorageResultCode.OperationSucceeded;
1017207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
1018207e538350665cea00e1aa70b8094beca4a34e45San Mehat            // Don't worry about mismatch in PackageManager since the
1019207e538350665cea00e1aa70b8094beca4a34e45San Mehat            // call back will handle the status changes any way.
1020207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
1021207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedVolNotMounted) {
1022a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageNotMounted;
1023d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else if (code == VoldResponseCode.OpFailedStorageBusy) {
1024d970998b0d489774ad1c5b94b47d233912f00214San Mehat                return StorageResultCode.OperationFailedStorageBusy;
1025207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
1026b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedInternalError;
1027207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
1028207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
1029207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
1030207e538350665cea00e1aa70b8094beca4a34e45San Mehat
1031207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private int doFormatVolume(String path) {
1032207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
1033dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("volume", "format", path);
1034b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return StorageResultCode.OperationSucceeded;
1035207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
1036207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
1037207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedNoMedia) {
1038b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedNoMedia;
1039207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
1040b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedMediaCorrupt;
1041207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
1042b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedInternalError;
1043207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
1044207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
1045207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
1046207e538350665cea00e1aa70b8094beca4a34e45San Mehat
1047b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private boolean doGetVolumeShared(String path, String method) {
1048dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
1049a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
1050dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("volume", "shared", path, method);
1051a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException ex) {
1052a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            Slog.e(TAG, "Failed to read response to volume shared " + path + " " + method);
1053a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            return false;
1054a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
1055b104340496e3a531e26c8f428c808eca0e039f50San Mehat
1056dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        if (event.getCode() == VoldResponseCode.ShareEnabledResult) {
1057dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return event.getMessage().endsWith("enabled");
1058dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        } else {
1059dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return false;
1060b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
1061b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
1062b104340496e3a531e26c8f428c808eca0e039f50San Mehat
1063ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood    private void notifyShareAvailabilityChange(final boolean avail) {
10644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
1065ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood            mUmsAvailable = avail;
10664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for (int i = mListeners.size() -1; i >= 0; i--) {
10674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                MountServiceBinderListener bl = mListeners.get(i);
10681f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                try {
1069b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    bl.mListener.onUsbMassStorageConnectionChanged(avail);
10704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (RemoteException rex) {
1071a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener dead");
10724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(i);
10731f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                } catch (Exception ex) {
1074a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener failed", ex);
10751f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                }
10761f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat            }
10774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        }
10787fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
1079b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (mSystemReady == true) {
10806a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat            sendUmsIntent(avail);
10816a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat        } else {
10826a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat            mSendUmsConnectedOnBoot = avail;
10831f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat        }
10842fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat
1085b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume primary = getPrimaryPhysicalVolume();
1086b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (avail == false && primary != null
1087b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                && Environment.MEDIA_SHARED.equals(getVolumeState(primary.getPath()))) {
1088b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final String path = primary.getPath();
10892fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            /*
10902fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat             * USB mass storage disconnected while enabled
10912fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat             */
10922fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            new Thread() {
10935af0b916f850486cff4797355bf9e7dc3352fe00Jason parks                @Override
10942fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                public void run() {
10952fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    try {
10962fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        int rc;
1097a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        Slog.w(TAG, "Disabling UMS after cable disconnect");
10982fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        doShareUnshareVolume(path, "ums", false);
10992fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
1100a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.e(TAG, String.format(
11012fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                                    "Failed to remount {%s} on UMS enabled-disconnect (%d)",
11022fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                                            path, rc));
11032fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        }
11042fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    } catch (Exception ex) {
1105a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        Slog.w(TAG, "Failed to mount media on UMS enabled-disconnect", ex);
11062fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    }
11072fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                }
11082fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            }.start();
11092fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat        }
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1112b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private void sendStorageIntent(String action, StorageVolume volume, UserHandle user) {
1113b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final Intent intent = new Intent(action, Uri.parse("file://" + volume.getPath()));
1114b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, volume);
1115b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        Slog.d(TAG, "sendStorageIntent " + intent + " to " + user);
1116b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mContext.sendBroadcastAsUser(intent, user);
1117a5250c93928e256738125b265e10c96c3575597eMike Lockwood    }
1118a5250c93928e256738125b265e10c96c3575597eMike Lockwood
11196a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private void sendUmsIntent(boolean c) {
11205ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        mContext.sendBroadcastAsUser(
11215ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn                new Intent((c ? Intent.ACTION_UMS_CONNECTED : Intent.ACTION_UMS_DISCONNECTED)),
11225ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn                UserHandle.ALL);
11236a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    }
11246a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat
1125207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void validatePermission(String perm) {
11264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
11274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            throw new SecurityException(String.format("Requires %s permission", perm));
11284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        }
11297fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
11307fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
11312f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    // Storage list XML tags
11322f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    private static final String TAG_STORAGE_LIST = "StorageList";
11332f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    private static final String TAG_STORAGE = "storage";
11342f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
1135b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private void readStorageListLocked() {
1136b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mVolumes.clear();
1137b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mVolumeStates.clear();
1138b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
113913fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio        Resources resources = mContext.getResources();
114013fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio
11412f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        int id = com.android.internal.R.xml.storage_list;
11422f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        XmlResourceParser parser = resources.getXml(id);
11432f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        AttributeSet attrs = Xml.asAttributeSet(parser);
11442f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
11452f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        try {
11462f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            XmlUtils.beginDocument(parser, TAG_STORAGE_LIST);
11472f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            while (true) {
11482f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                XmlUtils.nextElement(parser);
11492f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
11502f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                String element = parser.getName();
11512f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                if (element == null) break;
11522f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
11532f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                if (TAG_STORAGE.equals(element)) {
11542f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    TypedArray a = resources.obtainAttributes(attrs,
11552f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage);
11562f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
1157b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    String path = a.getString(
11582f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_mountPoint);
115913fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio                    int descriptionId = a.getResourceId(
116013fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio                            com.android.internal.R.styleable.Storage_storageDescription, -1);
11612f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    CharSequence description = a.getText(
11622f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_storageDescription);
11632f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    boolean primary = a.getBoolean(
11642f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_primary, false);
11652f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    boolean removable = a.getBoolean(
11662f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_removable, false);
11672f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    boolean emulated = a.getBoolean(
11682f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_emulated, false);
11692f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    int mtpReserve = a.getInt(
11702f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_mtpReserve, 0);
11718e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood                    boolean allowMassStorage = a.getBoolean(
11728e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood                            com.android.internal.R.styleable.Storage_allowMassStorage, false);
11737a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood                    // resource parser does not support longs, so XML value is in megabytes
11747a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood                    long maxFileSize = a.getInt(
11757a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood                            com.android.internal.R.styleable.Storage_maxFileSize, 0) * 1024L * 1024L;
11762f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
11772f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    Slog.d(TAG, "got storage path: " + path + " description: " + description +
11782f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            " primary: " + primary + " removable: " + removable +
11798e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood                            " emulated: " + emulated +  " mtpReserve: " + mtpReserve +
11807a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood                            " allowMassStorage: " + allowMassStorage +
11817a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood                            " maxFileSize: " + maxFileSize);
1182b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1183b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    if (emulated) {
1184b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        // For devices with emulated storage, we create separate
1185b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        // volumes for each known user.
1186b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        mEmulatedTemplate = new StorageVolume(null, descriptionId, true, false,
1187b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                                true, mtpReserve, false, maxFileSize, null);
1188b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1189b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        final UserManagerService userManager = UserManagerService.getInstance();
1190920ace0bbc2d4133dbec991d2636c99a57d6245eAmith Yamasani                        for (UserInfo user : userManager.getUsers(false)) {
1191b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            createEmulatedVolumeForUserLocked(user.getUserHandle());
11922f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        }
1193b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1194b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    } else {
1195b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        if (path == null || description == null) {
1196b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            Slog.e(TAG, "Missing storage path or description in readStorageList");
11972f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        } else {
1198b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            final StorageVolume volume = new StorageVolume(new File(path),
1199b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                                    descriptionId, primary, removable, emulated, mtpReserve,
1200b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                                    allowMassStorage, maxFileSize, null);
1201b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            addVolumeLocked(volume);
12022f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        }
12032f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    }
1204b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
12052f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    a.recycle();
12062f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                }
12072f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            }
12082f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        } catch (XmlPullParserException e) {
12092f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            throw new RuntimeException(e);
12102f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        } catch (IOException e) {
12112f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            throw new RuntimeException(e);
12122f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        } finally {
1213b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            // Compute storage ID for each physical volume; emulated storage is
1214b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            // always 0 when defined.
1215b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            int index = isExternalStorageEmulated() ? 1 : 0;
1216b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            for (StorageVolume volume : mVolumes) {
1217b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                if (!volume.isEmulated()) {
1218b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    volume.setStorageId(index++);
1219b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                }
1220fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood            }
12212f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            parser.close();
12222f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        }
12232f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    }
12242f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1226b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey     * Create and add new {@link StorageVolume} for given {@link UserHandle}
1227b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey     * using {@link #mEmulatedTemplate} as template.
1228b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey     */
1229b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private void createEmulatedVolumeForUserLocked(UserHandle user) {
1230b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (mEmulatedTemplate == null) {
1231b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            throw new IllegalStateException("Missing emulated volume multi-user template");
1232b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
1233b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1234b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final UserEnvironment userEnv = new UserEnvironment(user.getIdentifier());
1235b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final File path = userEnv.getExternalStorageDirectory();
1236b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume volume = StorageVolume.fromTemplate(mEmulatedTemplate, path, user);
1237b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        volume.setStorageId(0);
1238b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        addVolumeLocked(volume);
1239b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1240b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (mSystemReady) {
1241b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED);
1242b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        } else {
1243b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            // Place stub status for early callers to find
1244b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            mVolumeStates.put(volume.getPath(), Environment.MEDIA_MOUNTED);
1245b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
1246b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    }
1247b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1248b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private void addVolumeLocked(StorageVolume volume) {
1249b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        Slog.d(TAG, "addVolumeLocked() " + volume);
1250b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mVolumes.add(volume);
1251b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume existing = mVolumesByPath.put(volume.getPath(), volume);
1252b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (existing != null) {
1253b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            throw new IllegalStateException(
1254b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    "Volume at " + volume.getPath() + " already exists: " + existing);
1255b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
1256b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    }
1257b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1258b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private void removeVolumeLocked(StorageVolume volume) {
1259b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        Slog.d(TAG, "removeVolumeLocked() " + volume);
1260b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mVolumes.remove(volume);
1261b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mVolumesByPath.remove(volume.getPath());
1262b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mVolumeStates.remove(volume.getPath());
1263b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    }
1264b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1265b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private StorageVolume getPrimaryPhysicalVolume() {
1266b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
1267b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            for (StorageVolume volume : mVolumes) {
1268b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                if (volume.isPrimary() && !volume.isEmulated()) {
1269b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    return volume;
1270b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                }
1271b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            }
1272b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
1273b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        return null;
1274b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    }
1275b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1276b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    /**
1277207e538350665cea00e1aa70b8094beca4a34e45San Mehat     * Constructs a new MountService instance
1278207e538350665cea00e1aa70b8094beca4a34e45San Mehat     *
1279207e538350665cea00e1aa70b8094beca4a34e45San Mehat     * @param context  Binder context for this service
1280207e538350665cea00e1aa70b8094beca4a34e45San Mehat     */
1281207e538350665cea00e1aa70b8094beca4a34e45San Mehat    public MountService(Context context) {
1282207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mContext = context;
12832f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
1284b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
1285b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            readStorageListLocked();
128603559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood        }
128703559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood
1288207e538350665cea00e1aa70b8094beca4a34e45San Mehat        // XXX: This will go away soon in favor of IMountServiceObserver
1289207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mPms = (PackageManagerService) ServiceManager.getService("package");
1290207e538350665cea00e1aa70b8094beca4a34e45San Mehat
12915f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandlerThread = new HandlerThread("MountService");
12925f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandlerThread.start();
12935f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandler = new MountServiceHandler(mHandlerThread.getLooper());
12945f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler
1295b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        // Watch for user changes
1296b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final IntentFilter userFilter = new IntentFilter();
1297b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        userFilter.addAction(Intent.ACTION_USER_ADDED);
1298b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        userFilter.addAction(Intent.ACTION_USER_REMOVED);
1299b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
1300b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1301b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        // Watch for USB changes on primary volume
1302b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume primary = getPrimaryPhysicalVolume();
1303b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (primary != null && primary.allowMassStorage()) {
1304b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            mContext.registerReceiver(
1305b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_STATE), null, mHandler);
1306b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
1307b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1308a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        // Add OBB Action Handler to MountService thread.
1309a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());
1310a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1311c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen        /*
1312305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * Create the connection to vold with a maximum queue of twice the
1313305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * amount of containers we'd ever expect to have. This keeps an
1314305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * "asec list" from blocking a thread repeatedly.
1315305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         */
1316470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt        mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25);
131751a573c76737733638c475f52e441c814e6645ccKenny Root
1318305bcbf0c961840c4505770d084a1caacc074dbbKenny Root        Thread thread = new Thread(mConnector, VOLD_TAG);
1319207e538350665cea00e1aa70b8094beca4a34e45San Mehat        thread.start();
1320fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey
132107714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root        // Add ourself to the Watchdog monitors if enabled.
132207714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root        if (WATCHDOG_ENABLE) {
132307714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root            Watchdog.getInstance().addMonitor(this);
132407714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root        }
1325207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
1326207e538350665cea00e1aa70b8094beca4a34e45San Mehat
1327b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    public void systemReady() {
1328b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mSystemReady = true;
1329b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
1330b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    }
1331b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1332207e538350665cea00e1aa70b8094beca4a34e45San Mehat    /**
13334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Exposed API calls below here
13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13357fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
13364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public void registerListener(IMountServiceListener listener) {
13374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
13384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            MountServiceBinderListener bl = new MountServiceBinderListener(listener);
13394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            try {
13404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                listener.asBinder().linkToDeath(bl, 0);
13414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListeners.add(bl);
13424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } catch (RemoteException rex) {
1343a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to link to listener death");
13444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
13457fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public void unregisterListener(IMountServiceListener listener) {
13494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
13504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for(MountServiceBinderListener bl : mListeners) {
13514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                if (bl.mListener == listener) {
13524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(mListeners.indexOf(bl));
13535c25a2d338e9609d54e58cc1916c91cd8e9979abVairavan Srinivasan                    listener.asBinder().unlinkToDeath(bl, 0);
13544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    return;
13554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
13564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13606ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    public void shutdown(final IMountShutdownObserver observer) {
13614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.SHUTDOWN);
13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1363a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        Slog.i(TAG, "Shutting down");
1364b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
13657fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            for (String path : mVolumeStates.keySet()) {
13667fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                String state = mVolumeStates.get(path);
13677fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood
13687fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                if (state.equals(Environment.MEDIA_SHARED)) {
13697fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    /*
13707fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * If the media is currently shared, unshare it.
13717fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * XXX: This is still dangerous!. We should not
13727fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * be rebooting at *all* if UMS is enabled, since
13737fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * the UMS host could have dirty FAT cache entries
13747fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * yet to flush.
13757fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     */
13767fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    setUsbMassStorageEnabled(false);
13777fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                } else if (state.equals(Environment.MEDIA_CHECKING)) {
13787fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    /*
13797fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * If the media is being checked, then we need to wait for
13807fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * it to complete before being able to proceed.
13817fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     */
13827fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    // XXX: @hackbod - Should we disable the ANR timer here?
13837fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    int retries = 30;
13847fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
13857fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        try {
13867fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                            Thread.sleep(1000);
13877fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        } catch (InterruptedException iex) {
13887fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                            Slog.e(TAG, "Interrupted while waiting for media", iex);
13897fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                            break;
13907fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        }
13917fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        state = Environment.getExternalStorageState();
13927fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    }
13937fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    if (retries == 0) {
13947fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        Slog.e(TAG, "Timed out waiting for media to check");
13957fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    }
13964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
13977fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
13987fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                if (state.equals(Environment.MEDIA_MOUNTED)) {
13997fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    // Post a unmount message.
14007fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    ShutdownCallBack ucb = new ShutdownCallBack(path, observer);
14017fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
14027fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                } else if (observer != null) {
14037fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    /*
14047fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * Observer is waiting for onShutDownComplete when we are done.
14057fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * Since nothing will be done send notification directly so shutdown
14067fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * sequence can continue.
14077fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     */
14087fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    try {
14097fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        observer.onShutDownComplete(StorageResultCode.OperationSucceeded);
14107fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    } catch (RemoteException e) {
14117fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        Slog.w(TAG, "RemoteException when shutting down");
14127fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    }
14137fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                }
14145d0db4d356346bee68aec9a124df70dbaa9aaed1Johan Alfven            }
14151f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat        }
14169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14180eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private boolean getUmsEnabling() {
14190eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        synchronized (mListeners) {
14200eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            return mUmsEnabling;
14210eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
14220eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
14230eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
14240eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private void setUmsEnabling(boolean enable) {
14250eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        synchronized (mListeners) {
1426fc71125104650c61ab5b04f4c943de761d58cba6Tony Wu            mUmsEnabling = enable;
14270eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
14280eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
14290eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
1430b104340496e3a531e26c8f428c808eca0e039f50San Mehat    public boolean isUsbMassStorageConnected() {
1431207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
14327fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
14330eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (getUmsEnabling()) {
1434b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return true;
1435b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
1436ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood        synchronized (mListeners) {
1437ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood            return mUmsAvailable;
1438ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood        }
14394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14410eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    public void setUsbMassStorageEnabled(boolean enable) {
1442207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
14430eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
14440eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
1445b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume primary = getPrimaryPhysicalVolume();
1446b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (primary == null) return;
1447b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
14480eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        // TODO: Add support for multiple share methods
1449b104340496e3a531e26c8f428c808eca0e039f50San Mehat
14500eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        /*
14510eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         * If the volume is mounted and we're enabling then unmount it
14520eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         */
1453b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        String path = primary.getPath();
14540eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        String vs = getVolumeState(path);
14550eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        String method = "ums";
14560eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
14570eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            // Override for isUsbMassStorageEnabled()
14580eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            setUmsEnabling(enable);
14590eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true);
14600eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb));
14610eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            // Clear override
14620eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            setUmsEnabling(false);
14630eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
14640eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        /*
14650eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         * If we disabled UMS then mount the volume
14660eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         */
14670eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (!enable) {
14680eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            doShareUnshareVolume(path, method, enable);
14690eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
1470a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to remount " + path +
14710eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                        " after disabling share method " + method);
14720eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                /*
14730eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * Even though the mount failed, the unshare didn't so don't indicate an error.
14740eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * The mountVolume() call will have set the storage state and sent the necessary
14750eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * broadcasts.
14760eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 */
14770eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            }
14780eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
14794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1481b104340496e3a531e26c8f428c808eca0e039f50San Mehat    public boolean isUsbMassStorageEnabled() {
1482207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1483b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1484b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume primary = getPrimaryPhysicalVolume();
1485b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (primary != null) {
1486b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            return doGetVolumeShared(primary.getPath(), "ums");
1487b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        } else {
1488b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            return false;
1489b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14919ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
14934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * @return state of the volume at the specified mount point
14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
14954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String getVolumeState(String mountPoint) {
1496b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
14977fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            String state = mVolumeStates.get(mountPoint);
14987fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            if (state == null) {
14997fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
150018db5c5690472f9da6ce2d580067307378675809Ken Sumrall                if (SystemProperties.get("vold.encrypt_progress").length() != 0) {
150118db5c5690472f9da6ce2d580067307378675809Ken Sumrall                    state = Environment.MEDIA_REMOVED;
150218db5c5690472f9da6ce2d580067307378675809Ken Sumrall                } else {
150318db5c5690472f9da6ce2d580067307378675809Ken Sumrall                    throw new IllegalArgumentException();
150418db5c5690472f9da6ce2d580067307378675809Ken Sumrall                }
15057fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            }
15064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
15077fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            return state;
15087fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood        }
15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1511b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    @Override
1512e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root    public boolean isExternalStorageEmulated() {
1513b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        return mEmulatedTemplate != null;
1514e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root    }
1515e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root
15164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int mountVolume(String path) {
15174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1519207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1520207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return doMountVolume(path);
15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
152313c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo    public void unmountVolume(String path, boolean force, boolean removeEncryption) {
15244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1525207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15278a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        String volState = getVolumeState(path);
152813c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo        if (DEBUG_UNMOUNT) {
152913c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            Slog.i(TAG, "Unmounting " + path
153013c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo                    + " force = " + force
153113c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo                    + " removeEncryption = " + removeEncryption);
153213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo        }
15338a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        if (Environment.MEDIA_UNMOUNTED.equals(volState) ||
15348a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_REMOVED.equals(volState) ||
15358a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_SHARED.equals(volState) ||
15368a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_UNMOUNTABLE.equals(volState)) {
15378a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            // Media already unmounted or cannot be unmounted.
15388a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            // TODO return valid return code when adding observer call back.
15398a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            return;
15408a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
154113c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo        UnmountCallBack ucb = new UnmountCallBack(path, force, removeEncryption);
1542c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
15434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int formatVolume(String path) {
15464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1547207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
15489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1549207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return doFormatVolume(path);
15509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15513697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1552ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood    public int[] getStorageUsers(String path) {
1553c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1554c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        waitForReady();
1555c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        try {
1556dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            final String[] r = NativeDaemonEvent.filterMessageList(
1557dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                    mConnector.executeForList("storage", "users", path),
1558dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                    VoldResponseCode.StorageUsersListResult);
1559dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey
1560c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            // FMT: <pid> <process name>
1561c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            int[] data = new int[r.length];
1562c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            for (int i = 0; i < r.length; i++) {
1563dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                String[] tok = r[i].split(" ");
1564c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                try {
1565c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                    data[i] = Integer.parseInt(tok[0]);
1566c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                } catch (NumberFormatException nfe) {
1567a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
1568c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                    return new int[0];
1569c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                }
1570c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            }
1571c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            return data;
1572c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        } catch (NativeDaemonConnectorException e) {
1573a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Failed to retrieve storage users list", e);
1574c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            return new int[0];
1575c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        }
1576c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat    }
1577c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat
1578b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private void warnOnNotMounted() {
1579b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume primary = getPrimaryPhysicalVolume();
158032ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey        if (primary != null) {
158132ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey            boolean mounted = false;
158232ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey            try {
158332ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey                mounted = Environment.MEDIA_MOUNTED.equals(getVolumeState(primary.getPath()));
158432ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey            } catch (IllegalStateException e) {
158532ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey            }
158632ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey
158732ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey            if (!mounted) {
158832ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey                Slog.w(TAG, "getSecureContainerList() called when storage not mounted");
158932ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey            }
1590b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
1591b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
1592b104340496e3a531e26c8f428c808eca0e039f50San Mehat
15934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String[] getSecureContainerList() {
15944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
1595207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1596b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1597f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
15984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1599dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return NativeDaemonEvent.filterMessageList(
1600dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                    mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
16014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
16024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            return new String[0];
160302735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
16043697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
16053697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
16066dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root    public int createSecureContainer(String id, int sizeMb, String fstype, String key,
16076dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root            int ownerUid, boolean external) {
16084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_CREATE);
1609207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1610b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
16114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1612b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
16134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
16146dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root            mConnector.execute("asec", "create", id, sizeMb, fstype, key, ownerUid,
16156dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root                    external ? "1" : "0");
16164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1617b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
161802735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1619a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1620a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        if (rc == StorageResultCode.OperationSucceeded) {
1621a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            synchronized (mAsecMountSet) {
1622a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                mAsecMountSet.add(id);
1623a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1624a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
16254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
16263697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
16273697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
16284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int finalizeSecureContainer(String id) {
16294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_CREATE);
1630b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
16314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1632b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
16334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1634dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("asec", "finalize", id);
1635a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            /*
1636a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             * Finalization does a remount, so no need
1637a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             * to update mAsecMountSet
1638a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             */
16396dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        } catch (NativeDaemonConnectorException e) {
16406dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root            rc = StorageResultCode.OperationFailedInternalError;
16416dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        }
16426dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        return rc;
16436dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root    }
16446dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root
16456dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root    public int fixPermissionsSecureContainer(String id, int gid, String filename) {
16466dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        validatePermission(android.Manifest.permission.ASEC_CREATE);
16476dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        warnOnNotMounted();
16486dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root
16496dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        int rc = StorageResultCode.OperationSucceeded;
16506dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        try {
16516dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root            mConnector.execute("asec", "fixperms", id, gid, filename);
16526dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root            /*
16536dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root             * Fix permissions does a remount, so no need to update
16546dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root             * mAsecMountSet
16556dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root             */
16564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1657b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
165802735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
16594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
16603697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
16613697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1662d970998b0d489774ad1c5b94b47d233912f00214San Mehat    public int destroySecureContainer(String id, boolean force) {
16634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_DESTROY);
1664207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1665b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1666f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
1667aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
1668aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
1669aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
1670aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
1671aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
1672aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
1673aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
1674aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
1675b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
16764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1677dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            final Command cmd = new Command("asec", "destroy", id);
1678dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            if (force) {
1679dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                cmd.appendArg("force");
1680dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            }
1681dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute(cmd);
16824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1683d970998b0d489774ad1c5b94b47d233912f00214San Mehat            int code = e.getCode();
1684d970998b0d489774ad1c5b94b47d233912f00214San Mehat            if (code == VoldResponseCode.OpFailedStorageBusy) {
1685d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedStorageBusy;
1686d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else {
1687d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedInternalError;
1688d970998b0d489774ad1c5b94b47d233912f00214San Mehat            }
168902735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1690a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1691a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        if (rc == StorageResultCode.OperationSucceeded) {
1692a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            synchronized (mAsecMountSet) {
1693a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                if (mAsecMountSet.contains(id)) {
1694a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                    mAsecMountSet.remove(id);
1695a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                }
1696a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1697a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1698a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
16994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
17003697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
17019ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
17024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int mountSecureContainer(String id, String key, int ownerUid) {
17034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
1704207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1705b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
17064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1707a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        synchronized (mAsecMountSet) {
1708a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            if (mAsecMountSet.contains(id)) {
1709a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageMounted;
1710a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1711a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1712a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1713b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
17144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1715dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("asec", "mount", id, key, ownerUid);
17164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1717f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            int code = e.getCode();
1718f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            if (code != VoldResponseCode.OpFailedStorageBusy) {
1719f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root                rc = StorageResultCode.OperationFailedInternalError;
1720f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            }
172102735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
17226cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
17236cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        if (rc == StorageResultCode.OperationSucceeded) {
17246cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            synchronized (mAsecMountSet) {
17256cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat                mAsecMountSet.add(id);
17266cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
17276cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
17284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
17293697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
17303697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1731d970998b0d489774ad1c5b94b47d233912f00214San Mehat    public int unmountSecureContainer(String id, boolean force) {
17324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
1733207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1734b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
17354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
17366cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        synchronized (mAsecMountSet) {
17376cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            if (!mAsecMountSet.contains(id)) {
1738a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageNotMounted;
17396cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
17406cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat         }
17416cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
1742aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
1743aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
1744aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
1745aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
1746aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
1747aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
1748aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
1749aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
1750b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
17514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1752dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            final Command cmd = new Command("asec", "unmount", id);
1753dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            if (force) {
1754dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                cmd.appendArg("force");
1755dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            }
1756dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute(cmd);
17574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1758d970998b0d489774ad1c5b94b47d233912f00214San Mehat            int code = e.getCode();
1759d970998b0d489774ad1c5b94b47d233912f00214San Mehat            if (code == VoldResponseCode.OpFailedStorageBusy) {
1760d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedStorageBusy;
1761d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else {
1762d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedInternalError;
1763d970998b0d489774ad1c5b94b47d233912f00214San Mehat            }
176402735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
17656cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
17666cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        if (rc == StorageResultCode.OperationSucceeded) {
17676cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            synchronized (mAsecMountSet) {
17686cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat                mAsecMountSet.remove(id);
17696cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
17706cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
17714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
17729dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat    }
17739dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat
17746cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    public boolean isSecureContainerMounted(String id) {
17756cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
17766cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        waitForReady();
17776cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        warnOnNotMounted();
17786cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
17796cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        synchronized (mAsecMountSet) {
17806cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            return mAsecMountSet.contains(id);
17816cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
17826cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    }
17836cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
17844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int renameSecureContainer(String oldId, String newId) {
17854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_RENAME);
1786207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1787b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
17884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1789a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        synchronized (mAsecMountSet) {
179085451ee15fdf6cae371dc3005441988c7d426401San Mehat            /*
17919ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks             * Because a mounted container has active internal state which cannot be
179285451ee15fdf6cae371dc3005441988c7d426401San Mehat             * changed while active, we must ensure both ids are not currently mounted.
179385451ee15fdf6cae371dc3005441988c7d426401San Mehat             */
179485451ee15fdf6cae371dc3005441988c7d426401San Mehat            if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
1795a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageMounted;
1796a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1797a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1798a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1799b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
18004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1801dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("asec", "rename", oldId, newId);
18024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1803b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
180402735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1805a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
18064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
180745f61040823d8c442838f75cde8760f236603daeSan Mehat    }
180845f61040823d8c442838f75cde8760f236603daeSan Mehat
18094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String getSecureContainerPath(String id) {
18104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
1811207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1812b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1813f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
1814dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
18152d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        try {
1816dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("asec", "path", id);
1817dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event.checkCode(VoldResponseCode.AsecPathResult);
1818dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return event.getMessage();
18192d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        } catch (NativeDaemonConnectorException e) {
18202d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            int code = e.getCode();
18212d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            if (code == VoldResponseCode.OpFailedStorageNotFound) {
1822a20c8ef471666cf8b0dca91a8739ff18af1741a5Fredrik Helmer                Slog.i(TAG, String.format("Container '%s' not found", id));
1823a20c8ef471666cf8b0dca91a8739ff18af1741a5Fredrik Helmer                return null;
182422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            } else {
18252d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat                throw new IllegalStateException(String.format("Unexpected response code %d", code));
182622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            }
182722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
182822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
1829292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn
1830292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn    public String getSecureContainerFilesystemPath(String id) {
1831292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        validatePermission(android.Manifest.permission.ASEC_ACCESS);
1832292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        waitForReady();
1833292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        warnOnNotMounted();
1834292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn
1835dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
1836292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        try {
1837dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("asec", "fspath", id);
1838dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event.checkCode(VoldResponseCode.AsecPathResult);
1839dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return event.getMessage();
1840292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        } catch (NativeDaemonConnectorException e) {
1841292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn            int code = e.getCode();
1842292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn            if (code == VoldResponseCode.OpFailedStorageNotFound) {
1843292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn                Slog.i(TAG, String.format("Container '%s' not found", id));
1844292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn                return null;
1845292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn            } else {
1846292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn                throw new IllegalStateException(String.format("Unexpected response code %d", code));
1847292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn            }
1848292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        }
1849292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn    }
1850e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu
1851e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu    public void finishMediaUpdate() {
1852e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
1853e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu    }
185402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1855a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
1856a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        if (callerUid == android.os.Process.SYSTEM_UID) {
1857a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return true;
1858a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1859a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
186002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        if (packageName == null) {
186102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            return false;
186202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
186302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1864f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        final int packageUid = mPms.getPackageUid(packageName, UserHandle.getUserId(callerUid));
186502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
186602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        if (DEBUG_OBB) {
186702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
186802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root                    packageUid + ", callerUid = " + callerUid);
186902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
187002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
187102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        return callerUid == packageUid;
187202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
187302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
18744fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    public String getMountedObbPath(String rawPath) {
18754fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
1876af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
187702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        waitForReady();
187802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        warnOnNotMounted();
187902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
18804fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final ObbState state;
18814fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        synchronized (mObbPathToStateMap) {
18824fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            state = mObbPathToStateMap.get(rawPath);
18834fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        }
18844fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        if (state == null) {
18854fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            Slog.w(TAG, "Failed to find OBB mounted at " + rawPath);
18864fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            return null;
18874fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        }
18884fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
1889dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
189002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        try {
18914fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            event = mConnector.execute("obb", "path", state.voldPath);
1892dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event.checkCode(VoldResponseCode.AsecPathResult);
1893dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return event.getMessage();
189402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        } catch (NativeDaemonConnectorException e) {
189502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            int code = e.getCode();
189602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            if (code == VoldResponseCode.OpFailedStorageNotFound) {
1897a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                return null;
189802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            } else {
189902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root                throw new IllegalStateException(String.format("Unexpected response code %d", code));
190002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
190102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
190202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
190302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
19044fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    @Override
19054fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    public boolean isObbMounted(String rawPath) {
19064fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
1907a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        synchronized (mObbMounts) {
19084fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            return mObbPathToStateMap.containsKey(rawPath);
1909a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1910a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
1911a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
19124fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    @Override
19134fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    public void mountObb(
19144fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) {
19154fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
19164fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
19174fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        Preconditions.checkNotNull(token, "token cannot be null");
19184fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
19194fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final int callingUid = Binder.getCallingUid();
19204fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce);
19214fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final ObbAction action = new MountObbAction(obbState, key, callingUid);
1922a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
1923a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1924a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        if (DEBUG_OBB)
1925a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            Slog.i(TAG, "Send to OBB handler: " + action.toString());
192602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
192702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
19284fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    @Override
19294fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
19304fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
19314fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
19324fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final ObbState existingState;
19334fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        synchronized (mObbPathToStateMap) {
19344fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            existingState = mObbPathToStateMap.get(rawPath);
1935f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root        }
1936f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root
19374fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        if (existingState != null) {
19384fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            // TODO: separate state object from request data
19394fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            final int callingUid = Binder.getCallingUid();
19404fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            final ObbState newState = new ObbState(
19414fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                    rawPath, existingState.canonicalPath, callingUid, token, nonce);
19424fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            final ObbAction action = new UnmountObbAction(newState, force);
19434fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
1944a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
19454fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            if (DEBUG_OBB)
19464fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                Slog.i(TAG, "Send to OBB handler: " + action.toString());
19474fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        } else {
19484fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            Slog.w(TAG, "Unknown OBB mount at " + rawPath);
19494fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        }
1950a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
195102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1952444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo    @Override
1953444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo    public int getEncryptionState() {
1954444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
1955444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo                "no permission to access the crypt keeper");
1956444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo
1957444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        waitForReady();
1958444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo
1959dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
1960444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        try {
1961dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("cryptfs", "cryptocomplete");
1962dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return Integer.parseInt(event.getMessage());
1963444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        } catch (NumberFormatException e) {
1964444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            // Bad result - unexpected.
1965444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
1966444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            return ENCRYPTION_STATE_ERROR_UNKNOWN;
1967444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        } catch (NativeDaemonConnectorException e) {
1968444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            // Something bad happened.
1969444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            Slog.w(TAG, "Error in communicating with cryptfs in validating");
1970444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            return ENCRYPTION_STATE_ERROR_UNKNOWN;
1971444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        }
1972444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo    }
1973444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo
1974444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo    @Override
19755af0b916f850486cff4797355bf9e7dc3352fe00Jason parks    public int decryptStorage(String password) {
1976f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (TextUtils.isEmpty(password)) {
1977f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            throw new IllegalArgumentException("password cannot be empty");
19785af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        }
19795af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
19808888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
19818888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks                "no permission to access the crypt keeper");
19825af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
19835af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        waitForReady();
19845af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
19855af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        if (DEBUG_EVENTS) {
19865af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            Slog.i(TAG, "decrypting storage...");
19875af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        }
19885af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
1989dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
19905af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        try {
1991dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("cryptfs", "checkpw", password);
19929ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
1993da6aedf716bfdd40148823fb63d666d34b7b425eFredrik Roubert            final int code = Integer.parseInt(event.getMessage());
19949ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            if (code == 0) {
19959ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                // Decrypt was successful. Post a delayed message before restarting in order
19969ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                // to let the UI to clear itself
19979ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                mHandler.postDelayed(new Runnable() {
19989ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                    public void run() {
199931c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey                        try {
2000dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                            mConnector.execute("cryptfs", "restart");
200131c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey                        } catch (NativeDaemonConnectorException e) {
200231c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey                            Slog.e(TAG, "problem executing in background", e);
200331c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey                        }
20049ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                    }
2005f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks                }, 1000); // 1 second
20069ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            }
20079ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
20089ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            return code;
20095af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        } catch (NativeDaemonConnectorException e) {
20105af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            // Decryption failed
20115af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            return e.getCode();
20125af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        }
20135af0b916f850486cff4797355bf9e7dc3352fe00Jason parks    }
20145af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
201556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks    public int encryptStorage(String password) {
2016f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (TextUtils.isEmpty(password)) {
2017f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            throw new IllegalArgumentException("password cannot be empty");
201856aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        }
201956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
20208888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
20218888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks            "no permission to access the crypt keeper");
202256aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
202356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        waitForReady();
202456aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
202556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        if (DEBUG_EVENTS) {
20268888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks            Slog.i(TAG, "encrypting storage...");
202756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        }
202856aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
202956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        try {
2030dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("cryptfs", "enablecrypto", "inplace", password);
203156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        } catch (NativeDaemonConnectorException e) {
203256aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks            // Encryption failed
203356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks            return e.getCode();
203456aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        }
203556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
203656aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        return 0;
203756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks    }
203856aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
2039f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks    public int changeEncryptionPassword(String password) {
2040f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (TextUtils.isEmpty(password)) {
2041f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            throw new IllegalArgumentException("password cannot be empty");
2042f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        }
2043f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
2044f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2045f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            "no permission to access the crypt keeper");
2046f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
2047f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        waitForReady();
2048f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
2049f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (DEBUG_EVENTS) {
2050f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            Slog.i(TAG, "changing encryption password...");
2051f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        }
2052f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
2053dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
2054f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        try {
2055dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("cryptfs", "changepw", password);
2056dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return Integer.parseInt(event.getMessage());
2057f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        } catch (NativeDaemonConnectorException e) {
2058f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            // Encryption failed
2059f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            return e.getCode();
2060f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        }
2061f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks    }
2062f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
206332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate    /**
206432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate     * Validate a user-supplied password string with cryptfs
206532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate     */
206632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate    @Override
206732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate    public int verifyEncryptionPassword(String password) throws RemoteException {
206832418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        // Only the system process is permitted to validate passwords
206932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
207032418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            throw new SecurityException("no permission to access the crypt keeper");
207132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        }
207232418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
207332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
207432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            "no permission to access the crypt keeper");
207532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
207632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        if (TextUtils.isEmpty(password)) {
207732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            throw new IllegalArgumentException("password cannot be empty");
207832418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        }
207932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
208032418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        waitForReady();
208132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
208232418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        if (DEBUG_EVENTS) {
208332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            Slog.i(TAG, "validating encryption password...");
208432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        }
208532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
2086dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
208732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        try {
2088dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("cryptfs", "verifypw", password);
2089dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
2090dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return Integer.parseInt(event.getMessage());
209132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        } catch (NativeDaemonConnectorException e) {
209232418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            // Encryption failed
209332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            return e.getCode();
209432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        }
209532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate    }
209632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
2097b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    @Override
2098b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    public StorageVolume[] getVolumeList() {
2099b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final int callingUserId = UserHandle.getCallingUserId();
2100b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final boolean accessAll = (mContext.checkPermission(
2101b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                android.Manifest.permission.ACCESS_ALL_EXTERNAL_STORAGE,
2102b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                Binder.getCallingPid(), Binder.getCallingUid()) == PERMISSION_GRANTED);
2103b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
2104b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
2105b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final ArrayList<StorageVolume> filtered = Lists.newArrayList();
2106b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            for (StorageVolume volume : mVolumes) {
2107b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                final UserHandle owner = volume.getOwner();
2108b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                final boolean ownerMatch = owner == null || owner.getIdentifier() == callingUserId;
2109b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                if (accessAll || ownerMatch) {
2110b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    filtered.add(volume);
2111b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                }
21128fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood            }
2113b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            return filtered.toArray(new StorageVolume[filtered.size()]);
21148fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood        }
21158fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood    }
21168fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood
2117af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private void addObbStateLocked(ObbState obbState) throws RemoteException {
2118af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IBinder binder = obbState.getBinder();
2119af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        List<ObbState> obbStates = mObbMounts.get(binder);
21205919ac6b4188285324646772501ef4b97b353cf4Kenny Root
2121af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (obbStates == null) {
2122af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbStates = new ArrayList<ObbState>();
2123af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            mObbMounts.put(binder, obbStates);
2124af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        } else {
2125af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            for (final ObbState o : obbStates) {
21264fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                if (o.rawPath.equals(obbState.rawPath)) {
2127af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    throw new IllegalStateException("Attempt to add ObbState twice. "
2128af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            + "This indicates an error in the MountService logic.");
21295919ac6b4188285324646772501ef4b97b353cf4Kenny Root                }
21305919ac6b4188285324646772501ef4b97b353cf4Kenny Root            }
213102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
213202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2133af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        obbStates.add(obbState);
2134af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        try {
2135af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbState.link();
2136af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        } catch (RemoteException e) {
2137af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            /*
2138af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * The binder died before we could link it, so clean up our state
2139af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * and return failure.
2140af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             */
2141af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbStates.remove(obbState);
2142af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.isEmpty()) {
2143af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mObbMounts.remove(binder);
214405105f7abe02b2dff91d6260b3628c8b97816babKenny Root            }
21455919ac6b4188285324646772501ef4b97b353cf4Kenny Root
2146af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            // Rethrow the error so mountObb can get it
2147af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw e;
214802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
2149af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
21504fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        mObbPathToStateMap.put(obbState.rawPath, obbState);
2151a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
215202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2153af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private void removeObbStateLocked(ObbState obbState) {
2154af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IBinder binder = obbState.getBinder();
2155af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final List<ObbState> obbStates = mObbMounts.get(binder);
2156af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (obbStates != null) {
2157af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.remove(obbState)) {
2158af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                obbState.unlink();
2159af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2160af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.isEmpty()) {
2161af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mObbMounts.remove(binder);
2162af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
216338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
2164af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
21654fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        mObbPathToStateMap.remove(obbState.rawPath);
216638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    }
216738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2168a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private class ObbActionHandler extends Handler {
2169a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private boolean mBound = false;
2170480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root        private final List<ObbAction> mActions = new LinkedList<ObbAction>();
2171a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2172a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbActionHandler(Looper l) {
2173a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(l);
2174a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2175a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2176a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
2177a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleMessage(Message msg) {
2178a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            switch (msg.what) {
2179a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_RUN_ACTION: {
2180480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                    final ObbAction action = (ObbAction) msg.obj;
2181a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2182a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
2183a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
2184a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2185a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // If a bind was already initiated we don't really
2186a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // need to do anything. The pending install
2187a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // will be processed later on.
2188a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (!mBound) {
2189a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // If this is the only one pending we might
2190a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // have to bind to the service again.
2191a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (!connectToService()) {
2192a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            Slog.e(TAG, "Failed to bind to media container service");
2193a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.handleError();
2194a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            return;
2195a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2196a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2197735de3b38abbd6564082a819377673ee593744a6Kenny Root
2198735de3b38abbd6564082a819377673ee593744a6Kenny Root                    mActions.add(action);
2199a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
2200a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2201a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_BOUND: {
2202a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
2203a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_BOUND");
2204a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (msg.obj != null) {
2205a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mContainerService = (IMediaContainerService) msg.obj;
2206a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2207a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mContainerService == null) {
2208a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Something seriously wrong. Bail out
2209a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.e(TAG, "Cannot bind to media container service");
2210a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        for (ObbAction action : mActions) {
2211a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            // Indicate service bind error
2212a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.handleError();
2213a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2214a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mActions.clear();
2215a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else if (mActions.size() > 0) {
2216480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                        final ObbAction action = mActions.get(0);
2217a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (action != null) {
2218a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.execute(this);
2219a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2220a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else {
2221a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Should never happen ideally.
2222a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.w(TAG, "Empty queue");
2223a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2224a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
2225a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2226a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_RECONNECT: {
2227a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
2228a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_RECONNECT");
2229a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() > 0) {
2230a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (mBound) {
2231a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            disconnectService();
2232a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2233a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (!connectToService()) {
2234a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            Slog.e(TAG, "Failed to bind to media container service");
2235a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            for (ObbAction action : mActions) {
2236a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                                // Indicate service bind error
2237a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                                action.handleError();
2238a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            }
2239a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            mActions.clear();
2240a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2241a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2242a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
2243a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2244a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_UNBIND: {
2245a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
2246a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_UNBIND");
2247a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2248a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // Delete pending install
2249a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() > 0) {
2250a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mActions.remove(0);
2251a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2252a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() == 0) {
2253a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (mBound) {
2254a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            disconnectService();
2255a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2256a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else {
2257a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // There are more pending requests in queue.
2258a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Just post MCS_BOUND message to trigger processing
2259a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // of next pending install.
2260a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
2261a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2262a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
2263a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2264af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                case OBB_FLUSH_MOUNT_STATE: {
2265af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    final String path = (String) msg.obj;
2266af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2267af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    if (DEBUG_OBB)
2268af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        Slog.i(TAG, "Flushing all OBB state for path " + path);
2269af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2270af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    synchronized (mObbMounts) {
2271af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
2272af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
22734fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                        final Iterator<ObbState> i = mObbPathToStateMap.values().iterator();
2274af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        while (i.hasNext()) {
22754fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                            final ObbState state = i.next();
2276af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2277af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            /*
2278af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * If this entry's source file is in the volume path
2279af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * that got unmounted, remove it because it's no
2280af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * longer valid.
2281af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             */
22824fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                            if (state.canonicalPath.startsWith(path)) {
22834fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                                obbStatesToRemove.add(state);
2284af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            }
2285af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        }
2286af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2287af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        for (final ObbState obbState : obbStatesToRemove) {
2288af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            if (DEBUG_OBB)
22894fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                                Slog.i(TAG, "Removing state for " + obbState.rawPath);
2290af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2291af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            removeObbStateLocked(obbState);
2292af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2293af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            try {
22944fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                                obbState.token.onObbResult(obbState.rawPath, obbState.nonce,
2295af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                        OnObbStateChangeListener.UNMOUNTED);
2296af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            } catch (RemoteException e) {
2297af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                Slog.i(TAG, "Couldn't send unmount notification for  OBB: "
22984fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                                        + obbState.rawPath);
2299af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            }
2300af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        }
2301af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    }
2302af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    break;
2303af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                }
230402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
230502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
230602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2307a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private boolean connectToService() {
2308a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
2309a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "Trying to bind to DefaultContainerService");
2310a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2311a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
2312a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) {
2313a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mBound = true;
2314a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                return true;
231502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
2316a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return false;
2317a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2318a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2319a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private void disconnectService() {
2320a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mContainerService = null;
2321a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mBound = false;
2322a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mContext.unbindService(mDefContainerConn);
232302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
232402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
232502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2326a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    abstract class ObbAction {
2327a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private static final int MAX_RETRIES = 3;
2328a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private int mRetries;
232902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2330a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbState mObbState;
2331a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2332a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbAction(ObbState obbState) {
2333a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbState = obbState;
233402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
233502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2336a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void execute(ObbActionHandler handler) {
2337a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            try {
2338a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
2339444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo                    Slog.i(TAG, "Starting to execute action: " + toString());
2340a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mRetries++;
2341a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (mRetries > MAX_RETRIES) {
2342a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
2343480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                    mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
2344a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    handleError();
2345a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    return;
2346a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                } else {
2347a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    handleExecute();
2348a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
2349a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "Posting install MCS_UNBIND");
2350a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
2351a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2352a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            } catch (RemoteException e) {
2353a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
2354a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.i(TAG, "Posting install MCS_RECONNECT");
2355a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
2356a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            } catch (Exception e) {
2357a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
2358a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.d(TAG, "Error handling OBB action", e);
2359a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                handleError();
236017eb6fb07cc6965f09c51adc70b3c291f57a784aKenny Root                mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
236102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
2362a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
236302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
236405105f7abe02b2dff91d6260b3628c8b97816babKenny Root        abstract void handleExecute() throws RemoteException, IOException;
2365a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        abstract void handleError();
236638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
236738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        protected ObbInfo getObbInfo() throws IOException {
236838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            ObbInfo obbInfo;
236938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            try {
23704fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                obbInfo = mContainerService.getObbInfo(mObbState.ownerPath);
237138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } catch (RemoteException e) {
237238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
23734fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                        + mObbState.ownerPath);
237438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                obbInfo = null;
237538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
237638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            if (obbInfo == null) {
23774fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                throw new IOException("Couldn't read OBB file: " + mObbState.ownerPath);
237838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
237938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return obbInfo;
238038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
238138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2382af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        protected void sendNewStatusOrIgnore(int status) {
2383af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (mObbState == null || mObbState.token == null) {
2384af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2385af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2386af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
238738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            try {
23884fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
238938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } catch (RemoteException e) {
239038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
239138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
239238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
2393a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
2394a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2395a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class MountObbAction extends ObbAction {
2396444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        private final String mKey;
23974fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        private final int mCallingUid;
2398a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
23994fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        MountObbAction(ObbState obbState, String key, int callingUid) {
2400a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(obbState);
2401a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mKey = key;
24024fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            mCallingUid = callingUid;
2403a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2404a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
24055af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
2406735de3b38abbd6564082a819377673ee593744a6Kenny Root        public void handleExecute() throws IOException, RemoteException {
2407af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            waitForReady();
2408af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            warnOnNotMounted();
2409af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
241038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            final ObbInfo obbInfo = getObbInfo();
241138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
24124fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
2413af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
2414af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        + " which is owned by " + obbInfo.packageName);
2415af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
2416af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2417af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2418af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2419af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final boolean isMounted;
2420af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            synchronized (mObbMounts) {
24214fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
2422af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2423af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (isMounted) {
2424af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
2425af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
2426af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2427af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2428af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2429af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final String hashedKey;
2430af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (mKey == null) {
2431af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                hashedKey = "none";
2432af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } else {
2433af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                try {
24343b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
24353b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
24363b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
24373b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                            PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
24383b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    SecretKey key = factory.generateSecret(ks);
24393b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    BigInteger bi = new BigInteger(key.getEncoded());
24403b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    hashedKey = bi.toString(16);
2441af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } catch (NoSuchAlgorithmException e) {
24423b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
24433b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
24443b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    return;
24453b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                } catch (InvalidKeySpecException e) {
24463b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
24473b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
2448af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    return;
244938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                }
2450a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
2451a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2452af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            int rc = StorageResultCode.OperationSucceeded;
2453af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            try {
2454dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                mConnector.execute(
24554fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                        "obb", "mount", mObbState.voldPath, hashedKey, mObbState.ownerGid);
2456af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } catch (NativeDaemonConnectorException e) {
2457af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                int code = e.getCode();
2458af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (code != VoldResponseCode.OpFailedStorageBusy) {
2459af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedInternalError;
2460a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2461af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2462a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2463af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (rc == StorageResultCode.OperationSucceeded) {
2464af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (DEBUG_OBB)
24654fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                    Slog.d(TAG, "Successfully mounted OBB " + mObbState.voldPath);
246638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2467af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                synchronized (mObbMounts) {
2468af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    addObbStateLocked(mObbState);
2469a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
247038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2471af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
247202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            } else {
247305105f7abe02b2dff91d6260b3628c8b97816babKenny Root                Slog.e(TAG, "Couldn't mount OBB file: " + rc);
2474a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2475af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
247602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
247702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
247802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
24795af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
2480a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleError() {
2481af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
248202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
2483a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2484a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
2485a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public String toString() {
2486a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            StringBuilder sb = new StringBuilder();
2487a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("MountObbAction{");
24884fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append(mObbState);
2489a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append('}');
2490a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return sb.toString();
2491a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2492a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
2493a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2494a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class UnmountObbAction extends ObbAction {
2495444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        private final boolean mForceUnmount;
2496a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2497a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        UnmountObbAction(ObbState obbState, boolean force) {
2498a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(obbState);
2499a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mForceUnmount = force;
2500a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2501a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
25025af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
250338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        public void handleExecute() throws IOException {
2504af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            waitForReady();
2505af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            warnOnNotMounted();
2506af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
250738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            final ObbInfo obbInfo = getObbInfo();
2508a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
25094fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            final ObbState existingState;
251038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            synchronized (mObbMounts) {
25114fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                existingState = mObbPathToStateMap.get(mObbState.rawPath);
2512af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
251338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
25144fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            if (existingState == null) {
2515af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
2516af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2517a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
2518a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
25194fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            if (existingState.ownerGid != mObbState.ownerGid) {
25204fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
25214fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                        + " (owned by GID " + existingState.ownerGid + ")");
2522af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
2523af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2524af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2525a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2526af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            int rc = StorageResultCode.OperationSucceeded;
2527af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            try {
25284fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                final Command cmd = new Command("obb", "unmount", mObbState.voldPath);
2529dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                if (mForceUnmount) {
2530dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                    cmd.appendArg("force");
2531dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                }
2532dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                mConnector.execute(cmd);
2533af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } catch (NativeDaemonConnectorException e) {
2534af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                int code = e.getCode();
2535af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (code == VoldResponseCode.OpFailedStorageBusy) {
2536af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedStorageBusy;
2537af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
2538af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    // If it's not mounted then we've already won.
2539af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationSucceeded;
2540af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } else {
2541af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedInternalError;
2542a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2543a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
254438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2545af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (rc == StorageResultCode.OperationSucceeded) {
2546af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                synchronized (mObbMounts) {
25474fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                    removeObbStateLocked(existingState);
2548af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                }
254938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2550af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
255138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } else {
25524fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                Slog.w(TAG, "Could not unmount OBB: " + existingState);
2553af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
255438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
2555a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2556a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
25575af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
2558a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleError() {
2559af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
2560a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2561a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2562a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
2563a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public String toString() {
2564a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            StringBuilder sb = new StringBuilder();
2565a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("UnmountObbAction{");
25664fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append(mObbState);
2567a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",force=");
2568a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mForceUnmount);
2569a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append('}');
2570a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return sb.toString();
2571a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
257202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
257338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
25744fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    // @VisibleForTesting
25754fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    public static String buildObbPath(final String canonicalPath, int userId, boolean forVold) {
25764fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        // TODO: allow caller to provide Environment for full testing
25774fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
25784fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        // Only adjust paths when storage is emulated
25794fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        if (!Environment.isExternalStorageEmulated()) {
25804fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            return canonicalPath;
25814fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        }
25824fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
25834fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        String path = canonicalPath.toString();
25844fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
25854fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        // First trim off any external storage prefix
25864fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final UserEnvironment userEnv = new UserEnvironment(userId);
25874fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
25884fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        // /storage/emulated/0
25894fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final String externalPath = userEnv.getExternalStorageDirectory().toString();
25904fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        // /storage/emulated_legacy
25914fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final String legacyExternalPath = Environment.getLegacyExternalStorageDirectory()
25924fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                .toString();
25934fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
25944fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        if (path.startsWith(externalPath)) {
25954fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            path = path.substring(externalPath.length() + 1);
25964fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        } else if (path.startsWith(legacyExternalPath)) {
25974fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            path = path.substring(legacyExternalPath.length() + 1);
25984fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        } else {
25994fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            return canonicalPath;
26004fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        }
26014fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
26024fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        // Handle special OBB paths on emulated storage
26034fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final String obbPath = "Android/obb";
26044fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        if (path.startsWith(obbPath)) {
26054fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            path = path.substring(obbPath.length() + 1);
26064fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
26074fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            if (forVold) {
26084fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                return new File(Environment.getEmulatedStorageObbSource(), path).toString();
26094fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            } else {
26104fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                final UserEnvironment ownerEnv = new UserEnvironment(UserHandle.USER_OWNER);
26114fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                return new File(ownerEnv.getExternalStorageObbDirectory(), path).toString();
26124fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            }
26134fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        }
26144fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
26154fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        // Handle normal external storage paths
26164fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        if (forVold) {
26174fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            return new File(Environment.getEmulatedStorageSource(userId), path).toString();
26184fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        } else {
26194fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            return new File(userEnv.getExternalStorageDirectory(), path).toString();
26204fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        }
26214fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    }
26224fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
262338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    @Override
262438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
262538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
262638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            pw.println("Permission Denial: can't dump ActivityManager from from pid="
262738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
262838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                    + " without permission " + android.Manifest.permission.DUMP);
262938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return;
263038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
263138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
263238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        synchronized (mObbMounts) {
2633af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("  mObbMounts:");
263438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2635af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet().iterator();
2636af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            while (binders.hasNext()) {
2637af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Entry<IBinder, List<ObbState>> e = binders.next();
2638af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print("    Key="); pw.println(e.getKey().toString());
2639af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                final List<ObbState> obbStates = e.getValue();
264038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                for (final ObbState obbState : obbStates) {
2641af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    pw.print("      "); pw.println(obbState.toString());
264238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                }
264338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
2644af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2645af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("");
2646af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("  mObbPathToStateMap:");
2647af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
2648af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            while (maps.hasNext()) {
2649af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                final Entry<String, ObbState> e = maps.next();
2650af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print("    "); pw.print(e.getKey());
2651af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print(" -> "); pw.println(e.getValue().toString());
2652af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
265338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
26544161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root
26554161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root        pw.println("");
26564161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root
2657b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
26584161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root            pw.println("  mVolumes:");
26594161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root
26604161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root            final int N = mVolumes.size();
26614161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root            for (int i = 0; i < N; i++) {
26624161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root                final StorageVolume v = mVolumes.get(i);
26634161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root                pw.print("    ");
26644161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root                pw.println(v.toString());
26654161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root            }
26664161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root        }
2667470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt
2668470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt        pw.println();
2669470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt        pw.println("  mConnection:");
2670470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt        mConnector.dump(fd, pw, args);
267138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    }
26729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2673fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey    /** {@inheritDoc} */
2674fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey    public void monitor() {
2675fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey        if (mConnector != null) {
2676fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey            mConnector.monitor();
2677fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey        }
2678fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey    }
2679fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey}
2680