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
608b2c3a14603d163d7564e6f60286995079687690Jeff Sharkeyimport com.android.internal.annotations.GuardedBy;
618b2c3a14603d163d7564e6f60286995079687690Jeff Sharkeyimport com.android.internal.annotations.VisibleForTesting;
62b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.internal.app.IMediaContainerService;
634fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkeyimport com.android.internal.util.Preconditions;
64b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.internal.util.XmlUtils;
65b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.server.NativeDaemonConnector.Command;
66b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.server.am.ActivityManagerService;
67b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.server.pm.PackageManagerService;
68b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.android.server.pm.UserManagerService;
69b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.google.android.collect.Lists;
70b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport com.google.android.collect.Maps;
71b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
722f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwoodimport org.xmlpull.v1.XmlPullParserException;
73a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
74b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkeyimport java.io.File;
7538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.FileDescriptor;
7605105f7abe02b2dff91d6260b3628c8b97816babKenny Rootimport java.io.IOException;
7738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.PrintWriter;
783b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.math.BigInteger;
79735de3b38abbd6564082a819377673ee593744a6Kenny Rootimport java.security.NoSuchAlgorithmException;
803b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.InvalidKeySpecException;
813b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.KeySpec;
8222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehatimport java.util.ArrayList;
83a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.HashMap;
846cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehatimport java.util.HashSet;
8538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Iterator;
86a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.LinkedList;
87a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.List;
88a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.Map;
8938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Map.Entry;
9051a573c76737733638c475f52e441c814e6645ccKenny Rootimport java.util.concurrent.CountDownLatch;
9151a573c76737733638c475f52e441c814e6645ccKenny Rootimport java.util.concurrent.TimeUnit;
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
933b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKey;
943b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKeyFactory;
953b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.spec.PBEKeySpec;
963b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
98b104340496e3a531e26c8f428c808eca0e039f50San Mehat * MountService implements back-end services for platform storage
99b104340496e3a531e26c8f428c808eca0e039f50San Mehat * management.
100b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @hide - Applications should use android.os.storage.StorageManager
101b104340496e3a531e26c8f428c808eca0e039f50San Mehat * to access the MountService.
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
103fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkeyclass MountService extends IMountService.Stub
104fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey        implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
1055af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
106b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    // TODO: listen for user creation/deletion
107b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
10840e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn    private static final boolean LOCAL_LOGD = false;
10940e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn    private static final boolean DEBUG_UNMOUNT = false;
11040e9f2922cae76ffcbc521481e5be8e80e8744efDianne Hackborn    private static final boolean DEBUG_EVENTS = false;
111b7db2726e91f1d9480359d0f83b9cb7769906b34Kenny Root    private static final boolean DEBUG_OBB = false;
11202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
11307714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root    // Disable this since it messes up long-running cryptfs operations.
11407714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root    private static final boolean WATCHDOG_ENABLE = false;
11507714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "MountService";
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
118305bcbf0c961840c4505770d084a1caacc074dbbKenny Root    private static final String VOLD_TAG = "VoldConnector";
119305bcbf0c961840c4505770d084a1caacc074dbbKenny Root
120cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root    /** Maximum number of ASEC containers allowed to be mounted. */
121cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root    private static final int MAX_CONTAINERS = 250;
122cf0b38ca6e5aa5efded7dbdbb623f6cd2746c96aKenny Root
1234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    /*
1244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Internal vold volume state constants
1254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     */
1267fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    class VolumeState {
1277fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Init       = -1;
1287fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int NoMedia    = 0;
1297fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Idle       = 1;
1307fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Pending    = 2;
1317fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Checking   = 3;
1327fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Mounted    = 4;
1337fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Unmounting = 5;
1347fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Formatting = 6;
1357fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Shared     = 7;
1367fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int SharedMnt  = 8;
1377fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
1387fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
1394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    /*
1404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Internal vold response code constants
1414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     */
14222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    class VoldResponseCode {
1434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 100 series - Requestion action was initiated; expect another reply
1454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         *              before proceeding with a new command.
1464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
14722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeListResult               = 110;
14822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int AsecListResult                 = 111;
149c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        public static final int StorageUsersListResult         = 112;
15022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
1514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 200 series - Requestion action has been successfully completed.
1534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
1544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int ShareStatusResult              = 210;
15522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int AsecPathResult                 = 211;
1564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int ShareEnabledResult             = 212;
15722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
1584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 400 series - Command was accepted, but the requested action
1604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         *              did not take place.
1614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
1624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedNoMedia                = 401;
1634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedMediaBlank             = 402;
1644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedMediaCorrupt           = 403;
1654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedVolNotMounted          = 404;
166d970998b0d489774ad1c5b94b47d233912f00214San Mehat        public static final int OpFailedStorageBusy            = 405;
1672d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        public static final int OpFailedStorageNotFound        = 406;
1684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 600 series - Unsolicited broadcasts.
1714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
17222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeStateChange              = 605;
17322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeDiskInserted             = 630;
17422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeDiskRemoved              = 631;
17522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeBadRemoval               = 632;
17622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
17722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
178b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private Context mContext;
179b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private NativeDaemonConnector mConnector;
180b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
181b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private final Object mVolumesLock = new Object();
182b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
183b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    /** When defined, base template for user-specific {@link StorageVolume}. */
184b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private StorageVolume mEmulatedTemplate;
185b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1868b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey    @GuardedBy("mVolumesLock")
187b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private final ArrayList<StorageVolume> mVolumes = Lists.newArrayList();
188b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    /** Map from path to {@link StorageVolume} */
1898b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey    @GuardedBy("mVolumesLock")
190b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private final HashMap<String, StorageVolume> mVolumesByPath = Maps.newHashMap();
191b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    /** Map from path to state */
1928b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey    @GuardedBy("mVolumesLock")
193b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private final HashMap<String, String> mVolumeStates = Maps.newHashMap();
194b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
195b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private volatile boolean mSystemReady = false;
196b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private PackageManagerService                 mPms;
1984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private boolean                               mUmsEnabling;
199ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood    private boolean                               mUmsAvailable = false;
2000eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    // Used as a lock for methods that register/unregister listeners.
2010eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    final private ArrayList<MountServiceBinderListener> mListeners =
2020eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            new ArrayList<MountServiceBinderListener>();
2030be607cda1aed67149963a1f602f399c79845cfdJeff Sharkey    private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
2040be607cda1aed67149963a1f602f399c79845cfdJeff Sharkey    private final CountDownLatch mAsecsScanned = new CountDownLatch(1);
2056a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private boolean                               mSendUmsConnectedOnBoot = false;
206fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapu
2076cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    /**
2086cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat     * Private hash of currently mounted secure containers.
2090eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu     * Used as a lock in methods to manipulate secure containers.
2106cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat     */
2110eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    final private HashSet<String> mAsecMountSet = new HashSet<String>();
2126cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
21302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    /**
2143b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * The size of the crypto algorithm key in bits for OBB files. Currently
2153b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * Twofish is used which takes 128-bit keys.
2163b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     */
2173b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
2183b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
2193b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    /**
2203b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * The number of times to run SHA1 in the PBKDF2 function for OBB files.
2213b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * 1024 is reasonably secure and not too slow.
2223b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     */
2233b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    private static final int PBKDF2_HASH_ROUNDS = 1024;
2243b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
2253b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    /**
226a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * Mounted OBB tracking information. Used to track the current state of all
227a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * OBBs.
228a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     */
229735de3b38abbd6564082a819377673ee593744a6Kenny Root    final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
2304fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
2314fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    /** Map from raw paths to {@link ObbState}. */
232a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
233a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
234a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class ObbState implements IBinder.DeathRecipient {
2354fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        public ObbState(String rawPath, String canonicalPath, int callingUid,
2364fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                IObbActionListener token, int nonce) {
2374fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            this.rawPath = rawPath;
2384fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            this.canonicalPath = canonicalPath.toString();
2394fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
2404fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            final int userId = UserHandle.getUserId(callingUid);
2414fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            this.ownerPath = buildObbPath(canonicalPath, userId, false);
2424fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            this.voldPath = buildObbPath(canonicalPath, userId, true);
2434fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
2444fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            this.ownerGid = UserHandle.getSharedAppGid(callingUid);
245af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            this.token = token;
246af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            this.nonce = nonce;
247a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
248a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2494fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final String rawPath;
2504fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final String canonicalPath;
2514fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final String ownerPath;
2524fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final String voldPath;
253a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2544fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final int ownerGid;
255a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
256af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        // Token of remote Binder caller
257af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IObbActionListener token;
258af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
259af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        // Identifier to pass back to the token
260af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final int nonce;
261a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
262735de3b38abbd6564082a819377673ee593744a6Kenny Root        public IBinder getBinder() {
263735de3b38abbd6564082a819377673ee593744a6Kenny Root            return token.asBinder();
264735de3b38abbd6564082a819377673ee593744a6Kenny Root        }
265735de3b38abbd6564082a819377673ee593744a6Kenny Root
266a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
267a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void binderDied() {
268a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            ObbAction action = new UnmountObbAction(this, true);
269a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
270735de3b38abbd6564082a819377673ee593744a6Kenny Root        }
271a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2725919ac6b4188285324646772501ef4b97b353cf4Kenny Root        public void link() throws RemoteException {
2735919ac6b4188285324646772501ef4b97b353cf4Kenny Root            getBinder().linkToDeath(this, 0);
2745919ac6b4188285324646772501ef4b97b353cf4Kenny Root        }
2755919ac6b4188285324646772501ef4b97b353cf4Kenny Root
2765919ac6b4188285324646772501ef4b97b353cf4Kenny Root        public void unlink() {
277735de3b38abbd6564082a819377673ee593744a6Kenny Root            getBinder().unlinkToDeath(this, 0);
278a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
27938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
28038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        @Override
28138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        public String toString() {
28238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            StringBuilder sb = new StringBuilder("ObbState{");
2834fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append("rawPath=").append(rawPath);
2844fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append(",canonicalPath=").append(canonicalPath);
2854fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append(",ownerPath=").append(ownerPath);
2864fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append(",voldPath=").append(voldPath);
2874fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append(",ownerGid=").append(ownerGid);
2884fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append(",token=").append(token);
2894fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append(",binder=").append(getBinder());
29038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append('}');
29138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return sb.toString();
29238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
293a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
294a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
295a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // OBB Action Handler
296a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private ObbActionHandler mObbActionHandler;
297a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
298a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // OBB action handler messages
299a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_RUN_ACTION = 1;
300a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_BOUND = 2;
301a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_UNBIND = 3;
302a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_RECONNECT = 4;
303af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private static final int OBB_FLUSH_MOUNT_STATE = 5;
304a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
305a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    /*
306a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * Default Container Service information
30702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root     */
308a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
309a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
310a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
311a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
312a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
313a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class DefaultContainerConnection implements ServiceConnection {
314a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void onServiceConnected(ComponentName name, IBinder service) {
315a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
316a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "onServiceConnected");
317a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
318a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
319a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
320a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
321a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void onServiceDisconnected(ComponentName name) {
322a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
323a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "onServiceDisconnected");
324a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
325a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    };
326a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
327a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // Used in the ObbActionHandler
328a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private IMediaContainerService mContainerService = null;
32902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
33002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    // Handler messages
331c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_PM_UPDATE = 1;
332c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_PM_DONE = 2;
333c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_MS = 3;
334b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private static final int H_SYSTEM_READY = 4;
335b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
336c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int RETRY_UNMOUNT_DELAY = 30; // in ms
337c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int MAX_UNMOUNT_RETRIES = 4;
338c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
339c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    class UnmountCallBack {
34005105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final String path;
34105105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final boolean force;
34213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo        final boolean removeEncryption;
343c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        int retries;
344c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
34513c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo        UnmountCallBack(String path, boolean force, boolean removeEncryption) {
346c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            retries = 0;
347c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            this.path = path;
348c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            this.force = force;
34913c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            this.removeEncryption = removeEncryption;
350c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        }
3510eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3520eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        void handleFinished() {
353a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path);
35413c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            doUnmountVolume(path, true, removeEncryption);
3550eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
3560eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
3570eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3580eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    class UmsEnableCallBack extends UnmountCallBack {
35905105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final String method;
3600eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3610eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        UmsEnableCallBack(String path, String method, boolean force) {
36213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            super(path, force, false);
3630eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            this.method = method;
3640eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
3650eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3660eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        @Override
3670eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        void handleFinished() {
3680eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            super.handleFinished();
3690eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            doShareUnshareVolume(path, method, true);
3700eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
371c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    }
372c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
3736ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    class ShutdownCallBack extends UnmountCallBack {
3746ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        IMountShutdownObserver observer;
3756ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        ShutdownCallBack(String path, IMountShutdownObserver observer) {
37613c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            super(path, true, false);
3776ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            this.observer = observer;
3786ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        }
3796ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3806ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        @Override
3816ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        void handleFinished() {
38213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            int ret = doUnmountVolume(path, true, removeEncryption);
3836ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            if (observer != null) {
3846ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                try {
3856ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    observer.onShutDownComplete(ret);
3866ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                } catch (RemoteException e) {
387a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.w(TAG, "RemoteException when shutting down");
3886ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                }
3896ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            }
3906ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        }
3916ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    }
3926ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3935f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler    class MountServiceHandler extends Handler {
394c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>();
395e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        boolean mUpdatingStatus = false;
3966ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3975f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        MountServiceHandler(Looper l) {
3985f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler            super(l);
3995f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        }
4005f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler
4015af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
402c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        public void handleMessage(Message msg) {
403c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            switch (msg.what) {
404c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                case H_UNMOUNT_PM_UPDATE: {
405a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_UPDATE");
406c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    UnmountCallBack ucb = (UnmountCallBack) msg.obj;
407c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    mForceUnmounts.add(ucb);
408a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, " registered = " + mUpdatingStatus);
4096ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    // Register only if needed.
410e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                    if (!mUpdatingStatus) {
411a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        if (DEBUG_UNMOUNT) Slog.i(TAG, "Updating external media status on PackageManager");
412e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                        mUpdatingStatus = true;
413e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                        mPms.updateExternalMediaStatus(false, true);
414c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    }
415c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
416c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
417c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                case H_UNMOUNT_PM_DONE: {
418a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_DONE");
419a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "Updated status. Processing requests");
420e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                    mUpdatingStatus = false;
4216ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int size = mForceUnmounts.size();
4226ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int sizeArr[] = new int[size];
4236ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int sizeArrN = 0;
4247af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    // Kill processes holding references first
4257af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    ActivityManagerService ams = (ActivityManagerService)
4267af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    ServiceManager.getService("activity");
4276ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    for (int i = 0; i < size; i++) {
4286ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        UnmountCallBack ucb = mForceUnmounts.get(i);
4296ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        String path = ucb.path;
4306ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        boolean done = false;
4316ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        if (!ucb.force) {
432c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                            done = true;
433c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        } else {
4346ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            int pids[] = getStorageUsers(path);
4356ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            if (pids == null || pids.length == 0) {
4366ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                                done = true;
4376ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            } else {
4386ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                                // Eliminate system process here?
439648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn                                ams.killPids(pids, "unmount media", true);
4407af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                // Confirm if file references have been freed.
4417af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                pids = getStorageUsers(path);
4427af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                if (pids == null || pids.length == 0) {
4437af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    done = true;
444c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                                }
445c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                            }
446c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        }
4477af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                        if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) {
4487af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            // Retry again
4497af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            Slog.i(TAG, "Retrying to kill storage users again");
4507af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            mHandler.sendMessageDelayed(
4517af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    mHandler.obtainMessage(H_UNMOUNT_PM_DONE,
4527af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                            ucb.retries++),
4537af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    RETRY_UNMOUNT_DELAY);
454c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        } else {
4556ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            if (ucb.retries >= MAX_UNMOUNT_RETRIES) {
4567af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                Slog.i(TAG, "Failed to unmount media inspite of " +
4577af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                        MAX_UNMOUNT_RETRIES + " retries. Forcibly killing processes now");
4586ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            }
4597af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            sizeArr[sizeArrN++] = i;
4607af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS,
4617af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    ucb));
462c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        }
463c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    }
4646ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    // Remove already processed elements from list.
4656ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    for (int i = (sizeArrN-1); i >= 0; i--) {
4666ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        mForceUnmounts.remove(sizeArr[i]);
4676ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    }
468c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
469c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
470b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                case H_UNMOUNT_MS: {
471a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_MS");
472c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    UnmountCallBack ucb = (UnmountCallBack) msg.obj;
4730eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                    ucb.handleFinished();
474c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
475c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
476b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                case H_SYSTEM_READY: {
477b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    try {
478b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        handleSystemReady();
479b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    } catch (Exception ex) {
480b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        Slog.e(TAG, "Boot-time mount exception", ex);
481b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    }
482b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    break;
483b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                }
484c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            }
485c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        }
486c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    };
487b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
488b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private final HandlerThread mHandlerThread;
489b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private final Handler mHandler;
490c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
49151a573c76737733638c475f52e441c814e6645ccKenny Root    void waitForAsecScan() {
49251a573c76737733638c475f52e441c814e6645ccKenny Root        waitForLatch(mAsecsScanned);
49351a573c76737733638c475f52e441c814e6645ccKenny Root    }
49451a573c76737733638c475f52e441c814e6645ccKenny Root
495207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void waitForReady() {
49651a573c76737733638c475f52e441c814e6645ccKenny Root        waitForLatch(mConnectedSignal);
49751a573c76737733638c475f52e441c814e6645ccKenny Root    }
49851a573c76737733638c475f52e441c814e6645ccKenny Root
49951a573c76737733638c475f52e441c814e6645ccKenny Root    private void waitForLatch(CountDownLatch latch) {
50051a573c76737733638c475f52e441c814e6645ccKenny Root        for (;;) {
50151a573c76737733638c475f52e441c814e6645ccKenny Root            try {
50251a573c76737733638c475f52e441c814e6645ccKenny Root                if (latch.await(5000, TimeUnit.MILLISECONDS)) {
503207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    return;
50451a573c76737733638c475f52e441c814e6645ccKenny Root                } else {
50551a573c76737733638c475f52e441c814e6645ccKenny Root                    Slog.w(TAG, "Thread " + Thread.currentThread().getName()
50651a573c76737733638c475f52e441c814e6645ccKenny Root                            + " still waiting for MountService ready...");
507207e538350665cea00e1aa70b8094beca4a34e45San Mehat                }
50851a573c76737733638c475f52e441c814e6645ccKenny Root            } catch (InterruptedException e) {
50951a573c76737733638c475f52e441c814e6645ccKenny Root                Slog.w(TAG, "Interrupt while waiting for MountService to be ready.");
510207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
511207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
5121f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat    }
51302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
514b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private void handleSystemReady() {
515b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        // Snapshot current volume states since it's not safe to call into vold
516b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        // while holding locks.
517b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final HashMap<String, String> snapshot;
518b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
519b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            snapshot = new HashMap<String, String>(mVolumeStates);
520b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
52191c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
522b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        for (Map.Entry<String, String> entry : snapshot.entrySet()) {
523b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final String path = entry.getKey();
524b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final String state = entry.getValue();
52522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
526b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            if (state.equals(Environment.MEDIA_UNMOUNTED)) {
527b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                int rc = doMountVolume(path);
528b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                if (rc != StorageResultCode.OperationSucceeded) {
529b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    Slog.e(TAG, String.format("Boot-time mount failed (%d)",
530b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            rc));
531b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                }
532b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            } else if (state.equals(Environment.MEDIA_SHARED)) {
533c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                /*
534b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                 * Bootstrap UMS enabled state since vold indicates
535b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                 * the volume is shared (runtime restart while ums enabled)
536c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                 */
537b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                notifyVolumeStateChange(null, path, VolumeState.NoMedia,
538b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        VolumeState.Shared);
539b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            }
540b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
541b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
542b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        // Push mounted state for all emulated storage
543b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
544b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            for (StorageVolume volume : mVolumes) {
545b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                if (volume.isEmulated()) {
546b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED);
547c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                }
548b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            }
549b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
55084338c4559cd675cc8727c44bd1b6ad485b1a272Mike Lockwood
551b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        /*
552b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey         * If UMS was connected on boot, send the connected event
553b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey         * now that we're up.
554b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey         */
555b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (mSendUmsConnectedOnBoot) {
556b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            sendUmsIntent(true);
557b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            mSendUmsConnectedOnBoot = false;
558b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
559b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    }
5606a254403235196692b1769d2fe281b0852c0cc25San Mehat
561b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
562b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        @Override
563b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        public void onReceive(Context context, Intent intent) {
564b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
565b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            if (userId == -1) return;
566b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final UserHandle user = new UserHandle(userId);
567b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
568b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final String action = intent.getAction();
569b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            if (Intent.ACTION_USER_ADDED.equals(action)) {
570b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                synchronized (mVolumesLock) {
571b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    createEmulatedVolumeForUserLocked(user);
572b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                }
573b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
574b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
575b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                synchronized (mVolumesLock) {
576b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    final List<StorageVolume> toRemove = Lists.newArrayList();
577b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    for (StorageVolume volume : mVolumes) {
578b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        if (user.equals(volume.getOwner())) {
579b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            toRemove.add(volume);
580fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                        }
581207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    }
582b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    for (StorageVolume volume : toRemove) {
583b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        removeVolumeLocked(volume);
584b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    }
585b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                }
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
589b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
590b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
591b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        @Override
592b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        public void onReceive(Context context, Intent intent) {
593b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            boolean available = (intent.getBooleanExtra(UsbManager.USB_CONNECTED, false) &&
594b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    intent.getBooleanExtra(UsbManager.USB_FUNCTION_MASS_STORAGE, false));
595b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            notifyShareAvailabilityChange(available);
596b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
597b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    };
598b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
5994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private final class MountServiceBinderListener implements IBinder.DeathRecipient {
6004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        final IMountServiceListener mListener;
60191c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
6024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        MountServiceBinderListener(IMountServiceListener listener) {
6034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mListener = listener;
60402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
60591c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat        }
60691c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
6074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public void binderDied() {
608a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!");
609a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            synchronized (mListeners) {
6104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListeners.remove(this);
6114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListener.asBinder().unlinkToDeath(this, 0);
61291c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat            }
61391c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat        }
61491c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat    }
61591c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
6160eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private void doShareUnshareVolume(String path, String method, boolean enable) {
6174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        // TODO: Add support for multiple share methods
6184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (!method.equals("ums")) {
6194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            throw new IllegalArgumentException(String.format("Method %s not supported", method));
6207fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
623dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("volume", enable ? "share" : "unshare", path, method);
6244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
625a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Failed to share/unshare", e);
62622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
629b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private void updatePublicVolumeState(StorageVolume volume, String state) {
630b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final String path = volume.getPath();
631b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final String oldState;
632b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
6337fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            oldState = mVolumeStates.put(path, state);
6347fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
635b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
6367fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood        if (state.equals(oldState)) {
6377fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            Slog.w(TAG, String.format("Duplicate state transition (%s -> %s) for %s",
6387fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    state, state, path));
639b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return;
640b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
641af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
6427fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood        Slog.d(TAG, "volume state changed for " + path + " (" + oldState + " -> " + state + ")");
6437fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood
644b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        // Tell PackageManager about changes to primary volume state, but only
645b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        // when not emulated.
646b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (volume.isPrimary() && !volume.isEmulated()) {
647b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            if (Environment.MEDIA_UNMOUNTED.equals(state)) {
648b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                mPms.updateExternalMediaStatus(false, false);
6497fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood
650b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                /*
651b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                 * Some OBBs might have been unmounted when this volume was
652b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                 * unmounted, so send a message to the handler to let it know to
653b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                 * remove those from the list of mounted OBBS.
654b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                 */
655b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
656b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        OBB_FLUSH_MOUNT_STATE, path));
657b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            } else if (Environment.MEDIA_MOUNTED.equals(state)) {
658b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                mPms.updateExternalMediaStatus(true, false);
65903559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood            }
6608a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
661b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
6624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
6634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for (int i = mListeners.size() -1; i >= 0; i--) {
6644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                MountServiceBinderListener bl = mListeners.get(i);
6654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                try {
666b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    bl.mListener.onStorageStateChanged(path, oldState, state);
6674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (RemoteException rex) {
668a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener dead");
6694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(i);
6704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (Exception ex) {
671a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener failed", ex);
6724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
67722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    /**
67822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     * Callback from NativeDaemonConnector
67922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     */
68022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    public void onDaemonConnected() {
6815b77dab23469273d41f9c530d947ac055765e6eaSan Mehat        /*
6825b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         * Since we'll be calling back into the NativeDaemonConnector,
6835b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         * we need to do our work in a new thread.
6845b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         */
68551a573c76737733638c475f52e441c814e6645ccKenny Root        new Thread("MountService#onDaemonConnected") {
6865af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            @Override
6877fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            public void run() {
6885b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                /**
6895b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                 * Determine media state and UMS detection status
6905b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                 */
6917fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                try {
692dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                    final String[] vols = NativeDaemonEvent.filterMessageList(
693dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                            mConnector.executeForList("volume", "list"),
694dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                            VoldResponseCode.VolumeListResult);
6955b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                    for (String volstr : vols) {
6965b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        String[] tok = volstr.split(" ");
6975b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        // FMT: <label> <mountpoint> <state>
6987fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        String path = tok[1];
6997fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        String state = Environment.MEDIA_REMOVED;
7007fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood
701b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        final StorageVolume volume;
702b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        synchronized (mVolumesLock) {
703b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            volume = mVolumesByPath.get(path);
704b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        }
705b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
7065b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        int st = Integer.parseInt(tok[2]);
7075b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        if (st == VolumeState.NoMedia) {
7085b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_REMOVED;
7095b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Idle) {
710207e538350665cea00e1aa70b8094beca4a34e45San Mehat                            state = Environment.MEDIA_UNMOUNTED;
7115b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Mounted) {
7125b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_MOUNTED;
713a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.i(TAG, "Media already mounted on daemon connection");
7145b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Shared) {
7155b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_SHARED;
716a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.i(TAG, "Media shared on daemon connection");
7175b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else {
7185b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            throw new Exception(String.format("Unexpected state %d", st));
7197fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                        }
7207fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood
7217fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        if (state != null) {
7227fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                            if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state);
723b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            updatePublicVolumeState(volume, state);
7247fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        }
725c2a39471642e31d7350910612e40d078b825173aSan Mehat                    }
7265b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                } catch (Exception e) {
727a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Error processing initial volume state", e);
728b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    final StorageVolume primary = getPrimaryPhysicalVolume();
729b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    if (primary != null) {
730b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        updatePublicVolumeState(primary, Environment.MEDIA_REMOVED);
731b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    }
7327fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                }
7337fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
734207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
7359ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                 * Now that we've done our initialization, release
736207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * the hounds!
737207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
73851a573c76737733638c475f52e441c814e6645ccKenny Root                mConnectedSignal.countDown();
73951a573c76737733638c475f52e441c814e6645ccKenny Root
74051a573c76737733638c475f52e441c814e6645ccKenny Root                // Let package manager load internal ASECs.
74151a573c76737733638c475f52e441c814e6645ccKenny Root                mPms.scanAvailableAsecs();
74251a573c76737733638c475f52e441c814e6645ccKenny Root
74351a573c76737733638c475f52e441c814e6645ccKenny Root                // Notify people waiting for ASECs to be scanned that it's done.
74451a573c76737733638c475f52e441c814e6645ccKenny Root                mAsecsScanned.countDown();
7457fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            }
7467fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }.start();
7477fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
7487fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
74922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    /**
75022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     * Callback from NativeDaemonConnector
75122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     */
75222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    public boolean onEvent(int code, String raw, String[] cooked) {
7538a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        if (DEBUG_EVENTS) {
7548a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            StringBuilder builder = new StringBuilder();
7558a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            builder.append("onEvent::");
7568a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            builder.append(" raw= " + raw);
7578a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            if (cooked != null) {
7588a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                builder.append(" cooked = " );
7598a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                for (String str : cooked) {
7608a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                    builder.append(" " + str);
7618a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                }
7628a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            }
763a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.i(TAG, builder.toString());
7648a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
76522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        if (code == VoldResponseCode.VolumeStateChange) {
7664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            /*
7674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * One of the volumes we're managing has changed state.
7684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * Format: "NNN Volume <label> <path> state changed
7694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * from <old_#> (<old_str>) to <new_#> (<new_str>)"
7704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             */
77122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            notifyVolumeStateChange(
77222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat                    cooked[2], cooked[3], Integer.parseInt(cooked[7]),
77322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat                            Integer.parseInt(cooked[10]));
7744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } else if ((code == VoldResponseCode.VolumeDiskInserted) ||
7754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                   (code == VoldResponseCode.VolumeDiskRemoved) ||
7764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                   (code == VoldResponseCode.VolumeBadRemoval)) {
77722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
77822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
77922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
780a5250c93928e256738125b265e10c96c3575597eMike Lockwood            String action = null;
7814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            final String label = cooked[2];
7824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            final String path = cooked[3];
7834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            int major = -1;
7844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            int minor = -1;
7854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
7864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            try {
7874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                String devComp = cooked[6].substring(1, cooked[6].length() -1);
7884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                String[] devTok = devComp.split(":");
7894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                major = Integer.parseInt(devTok[0]);
7904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                minor = Integer.parseInt(devTok[1]);
7914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } catch (Exception ex) {
792a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to parse major/minor", ex);
7934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
7944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
795b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final StorageVolume volume;
796b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final String state;
797b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            synchronized (mVolumesLock) {
798b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                volume = mVolumesByPath.get(path);
799b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                state = mVolumeStates.get(path);
800b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            }
801b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
8024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            if (code == VoldResponseCode.VolumeDiskInserted) {
8034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                new Thread() {
8045af0b916f850486cff4797355bf9e7dc3352fe00Jason parks                    @Override
8054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    public void run() {
8064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        try {
8074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                            int rc;
808b104340496e3a531e26c8f428c808eca0e039f50San Mehat                            if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
809a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                                Slog.w(TAG, String.format("Insertion mount failed (%d)", rc));
8104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                            }
8114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        } catch (Exception ex) {
812a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.w(TAG, "Failed to mount media on insertion", ex);
8134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        }
8144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    }
8154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }.start();
8164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else if (code == VoldResponseCode.VolumeDiskRemoved) {
8174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /*
8184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                 * This event gets trumped if we're already in BAD_REMOVAL state
8194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                 */
8204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
8214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    return true;
8224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
8234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /* Send the media unmounted event first */
824a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
825b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);
826b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                sendStorageIntent(Environment.MEDIA_UNMOUNTED, volume, UserHandle.ALL);
8274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
828a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed");
829b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                updatePublicVolumeState(volume, Environment.MEDIA_REMOVED);
830a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_REMOVED;
8314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else if (code == VoldResponseCode.VolumeBadRemoval) {
832a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
8334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /* Send the media unmounted event first */
834b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);
835a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_UNMOUNTED;
8364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
837a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal");
838b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                updatePublicVolumeState(volume, Environment.MEDIA_BAD_REMOVAL);
839a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_BAD_REMOVAL;
8404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else {
841a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Unknown code {%d}", code));
8424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
843a5250c93928e256738125b265e10c96c3575597eMike Lockwood
844a5250c93928e256738125b265e10c96c3575597eMike Lockwood            if (action != null) {
845b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                sendStorageIntent(action, volume, UserHandle.ALL);
846a5250c93928e256738125b265e10c96c3575597eMike Lockwood            }
84722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        } else {
84822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            return false;
84922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
8504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
8515f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        return true;
85222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
85322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
854207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void notifyVolumeStateChange(String label, String path, int oldState, int newState) {
855b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume volume;
856b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final String state;
857b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
858b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            volume = mVolumesByPath.get(path);
859b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            state = getVolumeState(path);
860b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
861b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
862b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChange::" + state);
8634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
864a5250c93928e256738125b265e10c96c3575597eMike Lockwood        String action = null;
8657fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
866bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood        if (oldState == VolumeState.Shared && newState != oldState) {
867a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent");
868b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            sendStorageIntent(Intent.ACTION_MEDIA_UNSHARED, volume, UserHandle.ALL);
869bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood        }
870bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood
8717fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        if (newState == VolumeState.Init) {
8727fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.NoMedia) {
8737fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            // NoMedia is handled via Disk Remove events
8747fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Idle) {
8755fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat            /*
8765fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or
8775fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             * if we're in the process of enabling UMS
8785fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             */
879b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            if (!state.equals(
880b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    Environment.MEDIA_BAD_REMOVAL) && !state.equals(
881b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            Environment.MEDIA_NOFS) && !state.equals(
8820eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                                    Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) {
883a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable");
884b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);
885a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_UNMOUNTED;
8867fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            }
8877fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Pending) {
8887fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Checking) {
889a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking");
890b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            updatePublicVolumeState(volume, Environment.MEDIA_CHECKING);
891a5250c93928e256738125b265e10c96c3575597eMike Lockwood            action = Intent.ACTION_MEDIA_CHECKING;
8927fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Mounted) {
893a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted");
894b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED);
895a5250c93928e256738125b265e10c96c3575597eMike Lockwood            action = Intent.ACTION_MEDIA_MOUNTED;
8967fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Unmounting) {
897a5250c93928e256738125b265e10c96c3575597eMike Lockwood            action = Intent.ACTION_MEDIA_EJECT;
8987fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Formatting) {
8997fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Shared) {
900a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted");
9014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            /* Send the media unmounted event first */
902b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTED);
903b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            sendStorageIntent(Intent.ACTION_MEDIA_UNMOUNTED, volume, UserHandle.ALL);
9044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
905a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared");
906b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            updatePublicVolumeState(volume, Environment.MEDIA_SHARED);
907a5250c93928e256738125b265e10c96c3575597eMike Lockwood            action = Intent.ACTION_MEDIA_SHARED;
908a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent");
9097fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.SharedMnt) {
910a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Live shared mounts not supported yet!");
9114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            return;
9127fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else {
913a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Unhandled VolumeState {" + newState + "}");
9147fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
9157fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
916a5250c93928e256738125b265e10c96c3575597eMike Lockwood        if (action != null) {
917b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            sendStorageIntent(action, volume, UserHandle.ALL);
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
921207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private int doMountVolume(String path) {
922b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
923207e538350665cea00e1aa70b8094beca4a34e45San Mehat
924b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume volume;
925b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
926b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            volume = mVolumesByPath.get(path);
927b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
928b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
929a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path);
930207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
931dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("volume", "mount", path);
932207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
933207e538350665cea00e1aa70b8094beca4a34e45San Mehat            /*
934207e538350665cea00e1aa70b8094beca4a34e45San Mehat             * Mount failed for some reason
935207e538350665cea00e1aa70b8094beca4a34e45San Mehat             */
936a5250c93928e256738125b265e10c96c3575597eMike Lockwood            String action = null;
937207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
938207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedNoMedia) {
939207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
940207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Attempt to mount but no media inserted
941207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
942b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedNoMedia;
943207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaBlank) {
944a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs");
945207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
946207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Media is blank or does not contain a supported filesystem
947207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
948b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                updatePublicVolumeState(volume, Environment.MEDIA_NOFS);
949a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_NOFS;
950b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedMediaBlank;
951207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
952a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state media corrupt");
953207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
954207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Volume consistency check failed
955207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
956b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                updatePublicVolumeState(volume, Environment.MEDIA_UNMOUNTABLE);
957a5250c93928e256738125b265e10c96c3575597eMike Lockwood                action = Intent.ACTION_MEDIA_UNMOUNTABLE;
958b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedMediaCorrupt;
959207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
960b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedInternalError;
961207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
962207e538350665cea00e1aa70b8094beca4a34e45San Mehat
963207e538350665cea00e1aa70b8094beca4a34e45San Mehat            /*
964207e538350665cea00e1aa70b8094beca4a34e45San Mehat             * Send broadcast intent (if required for the failure)
965207e538350665cea00e1aa70b8094beca4a34e45San Mehat             */
966a5250c93928e256738125b265e10c96c3575597eMike Lockwood            if (action != null) {
967b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                sendStorageIntent(action, volume, UserHandle.ALL);
968207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
969207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
970207e538350665cea00e1aa70b8094beca4a34e45San Mehat
971207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return rc;
972207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
973207e538350665cea00e1aa70b8094beca4a34e45San Mehat
974c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    /*
975c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * If force is not set, we do not unmount if there are
976c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * processes holding references to the volume about to be unmounted.
977c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * If force is set, all the processes holding references need to be
978c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * killed via the ActivityManager before actually unmounting the volume.
979c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * This might even take a while and might be retried after timed delays
980c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * to make sure we dont end up in an instable state and kill some core
981c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * processes.
98213c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo     * If removeEncryption is set, force is implied, and the system will remove any encryption
98313c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo     * mapping set on the volume when unmounting.
984c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     */
98513c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo    private int doUnmountVolume(String path, boolean force, boolean removeEncryption) {
98659443a673a736978361dc341f41ce4e9dae053a0San Mehat        if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
987207e538350665cea00e1aa70b8094beca4a34e45San Mehat            return VoldResponseCode.OpFailedVolNotMounted;
988207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
989aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
990aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
991aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
992aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
993aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
994aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
995aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
996aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
997aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
998c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        // Redundant probably. But no harm in updating state again.
999e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        mPms.updateExternalMediaStatus(false, false);
1000207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
1001dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            final Command cmd = new Command("volume", "unmount", path);
1002dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            if (removeEncryption) {
1003dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                cmd.appendArg("force_and_revert");
1004dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            } else if (force) {
1005dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                cmd.appendArg("force");
1006dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            }
1007dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute(cmd);
1008e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            // We unmounted the volume. None of the asec containers are available now.
1009e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            synchronized (mAsecMountSet) {
1010e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                mAsecMountSet.clear();
1011e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            }
1012b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return StorageResultCode.OperationSucceeded;
1013207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
1014207e538350665cea00e1aa70b8094beca4a34e45San Mehat            // Don't worry about mismatch in PackageManager since the
1015207e538350665cea00e1aa70b8094beca4a34e45San Mehat            // call back will handle the status changes any way.
1016207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
1017207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedVolNotMounted) {
1018a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageNotMounted;
1019d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else if (code == VoldResponseCode.OpFailedStorageBusy) {
1020d970998b0d489774ad1c5b94b47d233912f00214San Mehat                return StorageResultCode.OperationFailedStorageBusy;
1021207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
1022b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedInternalError;
1023207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
1024207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
1025207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
1026207e538350665cea00e1aa70b8094beca4a34e45San Mehat
1027207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private int doFormatVolume(String path) {
1028207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
1029dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("volume", "format", path);
1030b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return StorageResultCode.OperationSucceeded;
1031207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
1032207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
1033207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedNoMedia) {
1034b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedNoMedia;
1035207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
1036b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedMediaCorrupt;
1037207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
1038b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedInternalError;
1039207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
1040207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
1041207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
1042207e538350665cea00e1aa70b8094beca4a34e45San Mehat
1043b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private boolean doGetVolumeShared(String path, String method) {
1044dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
1045a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
1046dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("volume", "shared", path, method);
1047a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException ex) {
1048a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            Slog.e(TAG, "Failed to read response to volume shared " + path + " " + method);
1049a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            return false;
1050a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
1051b104340496e3a531e26c8f428c808eca0e039f50San Mehat
1052dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        if (event.getCode() == VoldResponseCode.ShareEnabledResult) {
1053dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return event.getMessage().endsWith("enabled");
1054dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        } else {
1055dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return false;
1056b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
1057b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
1058b104340496e3a531e26c8f428c808eca0e039f50San Mehat
1059ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood    private void notifyShareAvailabilityChange(final boolean avail) {
10604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
1061ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood            mUmsAvailable = avail;
10624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for (int i = mListeners.size() -1; i >= 0; i--) {
10634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                MountServiceBinderListener bl = mListeners.get(i);
10641f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                try {
1065b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    bl.mListener.onUsbMassStorageConnectionChanged(avail);
10664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (RemoteException rex) {
1067a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener dead");
10684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(i);
10691f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                } catch (Exception ex) {
1070a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener failed", ex);
10711f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                }
10721f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat            }
10734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        }
10747fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
1075b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (mSystemReady == true) {
10766a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat            sendUmsIntent(avail);
10776a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat        } else {
10786a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat            mSendUmsConnectedOnBoot = avail;
10791f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat        }
10802fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat
1081b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume primary = getPrimaryPhysicalVolume();
1082b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (avail == false && primary != null
1083b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                && Environment.MEDIA_SHARED.equals(getVolumeState(primary.getPath()))) {
1084b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final String path = primary.getPath();
10852fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            /*
10862fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat             * USB mass storage disconnected while enabled
10872fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat             */
10882fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            new Thread() {
10895af0b916f850486cff4797355bf9e7dc3352fe00Jason parks                @Override
10902fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                public void run() {
10912fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    try {
10922fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        int rc;
1093a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        Slog.w(TAG, "Disabling UMS after cable disconnect");
10942fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        doShareUnshareVolume(path, "ums", false);
10952fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
1096a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.e(TAG, String.format(
10972fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                                    "Failed to remount {%s} on UMS enabled-disconnect (%d)",
10982fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                                            path, rc));
10992fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        }
11002fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    } catch (Exception ex) {
1101a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        Slog.w(TAG, "Failed to mount media on UMS enabled-disconnect", ex);
11022fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    }
11032fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                }
11042fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            }.start();
11052fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat        }
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1108b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private void sendStorageIntent(String action, StorageVolume volume, UserHandle user) {
1109b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final Intent intent = new Intent(action, Uri.parse("file://" + volume.getPath()));
1110b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, volume);
1111b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        Slog.d(TAG, "sendStorageIntent " + intent + " to " + user);
1112b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mContext.sendBroadcastAsUser(intent, user);
1113a5250c93928e256738125b265e10c96c3575597eMike Lockwood    }
1114a5250c93928e256738125b265e10c96c3575597eMike Lockwood
11156a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private void sendUmsIntent(boolean c) {
11165ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        mContext.sendBroadcastAsUser(
11175ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn                new Intent((c ? Intent.ACTION_UMS_CONNECTED : Intent.ACTION_UMS_DISCONNECTED)),
11185ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn                UserHandle.ALL);
11196a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    }
11206a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat
1121207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void validatePermission(String perm) {
11224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
11234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            throw new SecurityException(String.format("Requires %s permission", perm));
11244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        }
11257fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
11267fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
11272f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    // Storage list XML tags
11282f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    private static final String TAG_STORAGE_LIST = "StorageList";
11292f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    private static final String TAG_STORAGE = "storage";
11302f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
1131b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private void readStorageListLocked() {
1132b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mVolumes.clear();
1133b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mVolumeStates.clear();
1134b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
113513fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio        Resources resources = mContext.getResources();
113613fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio
11372f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        int id = com.android.internal.R.xml.storage_list;
11382f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        XmlResourceParser parser = resources.getXml(id);
11392f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        AttributeSet attrs = Xml.asAttributeSet(parser);
11402f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
11412f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        try {
11422f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            XmlUtils.beginDocument(parser, TAG_STORAGE_LIST);
11432f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            while (true) {
11442f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                XmlUtils.nextElement(parser);
11452f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
11462f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                String element = parser.getName();
11472f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                if (element == null) break;
11482f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
11492f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                if (TAG_STORAGE.equals(element)) {
11502f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    TypedArray a = resources.obtainAttributes(attrs,
11512f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage);
11522f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
1153b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    String path = a.getString(
11542f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_mountPoint);
115513fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio                    int descriptionId = a.getResourceId(
115613fe2a5330a5df662d7b1b136e7b08fe34c94a42Fabrice Di Meglio                            com.android.internal.R.styleable.Storage_storageDescription, -1);
11572f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    CharSequence description = a.getText(
11582f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_storageDescription);
11592f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    boolean primary = a.getBoolean(
11602f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_primary, false);
11612f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    boolean removable = a.getBoolean(
11622f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_removable, false);
11632f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    boolean emulated = a.getBoolean(
11642f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_emulated, false);
11652f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    int mtpReserve = a.getInt(
11662f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            com.android.internal.R.styleable.Storage_mtpReserve, 0);
11678e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood                    boolean allowMassStorage = a.getBoolean(
11688e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood                            com.android.internal.R.styleable.Storage_allowMassStorage, false);
11697a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood                    // resource parser does not support longs, so XML value is in megabytes
11707a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood                    long maxFileSize = a.getInt(
11717a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood                            com.android.internal.R.styleable.Storage_maxFileSize, 0) * 1024L * 1024L;
11722f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
11732f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    Slog.d(TAG, "got storage path: " + path + " description: " + description +
11742f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                            " primary: " + primary + " removable: " + removable +
11758e8b280bd19fa6cb69bb19e1d90cf03a47ba2d72Mike Lockwood                            " emulated: " + emulated +  " mtpReserve: " + mtpReserve +
11767a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood                            " allowMassStorage: " + allowMassStorage +
11777a59dd2ce33b46cbc73eef964ddb4272ea1da8d1Mike Lockwood                            " maxFileSize: " + maxFileSize);
1178b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1179b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    if (emulated) {
1180b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        // For devices with emulated storage, we create separate
1181b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        // volumes for each known user.
1182b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        mEmulatedTemplate = new StorageVolume(null, descriptionId, true, false,
1183b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                                true, mtpReserve, false, maxFileSize, null);
1184b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1185b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        final UserManagerService userManager = UserManagerService.getInstance();
1186920ace0bbc2d4133dbec991d2636c99a57d6245eAmith Yamasani                        for (UserInfo user : userManager.getUsers(false)) {
1187b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            createEmulatedVolumeForUserLocked(user.getUserHandle());
11882f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        }
1189b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1190b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    } else {
1191b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                        if (path == null || description == null) {
1192b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            Slog.e(TAG, "Missing storage path or description in readStorageList");
11932f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        } else {
1194b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            final StorageVolume volume = new StorageVolume(new File(path),
1195b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                                    descriptionId, primary, removable, emulated, mtpReserve,
1196b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                                    allowMassStorage, maxFileSize, null);
1197b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                            addVolumeLocked(volume);
11982f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                        }
11992f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    }
1200b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
12012f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                    a.recycle();
12022f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood                }
12032f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            }
12042f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        } catch (XmlPullParserException e) {
12052f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            throw new RuntimeException(e);
12062f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        } catch (IOException e) {
12072f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            throw new RuntimeException(e);
12082f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        } finally {
1209b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            // Compute storage ID for each physical volume; emulated storage is
1210b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            // always 0 when defined.
1211b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            int index = isExternalStorageEmulated() ? 1 : 0;
1212b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            for (StorageVolume volume : mVolumes) {
1213b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                if (!volume.isEmulated()) {
1214b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    volume.setStorageId(index++);
1215b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                }
1216fbfe55512596fd00c1fb51caa851e17dae60fd43Mike Lockwood            }
12172f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood            parser.close();
12182f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood        }
12192f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood    }
12202f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1222b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey     * Create and add new {@link StorageVolume} for given {@link UserHandle}
1223b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey     * using {@link #mEmulatedTemplate} as template.
1224b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey     */
1225b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private void createEmulatedVolumeForUserLocked(UserHandle user) {
1226b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (mEmulatedTemplate == null) {
1227b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            throw new IllegalStateException("Missing emulated volume multi-user template");
1228b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
1229b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1230b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final UserEnvironment userEnv = new UserEnvironment(user.getIdentifier());
1231b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final File path = userEnv.getExternalStorageDirectory();
1232b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume volume = StorageVolume.fromTemplate(mEmulatedTemplate, path, user);
1233b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        volume.setStorageId(0);
1234b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        addVolumeLocked(volume);
1235b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1236b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (mSystemReady) {
1237b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            updatePublicVolumeState(volume, Environment.MEDIA_MOUNTED);
1238b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        } else {
1239b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            // Place stub status for early callers to find
1240b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            mVolumeStates.put(volume.getPath(), Environment.MEDIA_MOUNTED);
1241b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
1242b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    }
1243b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1244b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private void addVolumeLocked(StorageVolume volume) {
1245b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        Slog.d(TAG, "addVolumeLocked() " + volume);
1246b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mVolumes.add(volume);
1247b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume existing = mVolumesByPath.put(volume.getPath(), volume);
1248b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (existing != null) {
1249b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            throw new IllegalStateException(
1250b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    "Volume at " + volume.getPath() + " already exists: " + existing);
1251b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
1252b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    }
1253b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1254b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private void removeVolumeLocked(StorageVolume volume) {
1255b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        Slog.d(TAG, "removeVolumeLocked() " + volume);
1256b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mVolumes.remove(volume);
1257b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mVolumesByPath.remove(volume.getPath());
1258b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mVolumeStates.remove(volume.getPath());
1259b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    }
1260b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1261b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    private StorageVolume getPrimaryPhysicalVolume() {
1262b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
1263b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            for (StorageVolume volume : mVolumes) {
1264b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                if (volume.isPrimary() && !volume.isEmulated()) {
1265b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    return volume;
1266b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                }
1267b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            }
1268b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
1269b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        return null;
1270b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    }
1271b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1272b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    /**
1273207e538350665cea00e1aa70b8094beca4a34e45San Mehat     * Constructs a new MountService instance
1274207e538350665cea00e1aa70b8094beca4a34e45San Mehat     *
1275207e538350665cea00e1aa70b8094beca4a34e45San Mehat     * @param context  Binder context for this service
1276207e538350665cea00e1aa70b8094beca4a34e45San Mehat     */
1277207e538350665cea00e1aa70b8094beca4a34e45San Mehat    public MountService(Context context) {
1278207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mContext = context;
12792f6a3885533a52758c2cd4f81f6123a712be8ae6Mike Lockwood
1280b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
1281b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            readStorageListLocked();
128203559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood        }
128303559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood
1284207e538350665cea00e1aa70b8094beca4a34e45San Mehat        // XXX: This will go away soon in favor of IMountServiceObserver
1285207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mPms = (PackageManagerService) ServiceManager.getService("package");
1286207e538350665cea00e1aa70b8094beca4a34e45San Mehat
12875f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandlerThread = new HandlerThread("MountService");
12885f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandlerThread.start();
12895f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandler = new MountServiceHandler(mHandlerThread.getLooper());
12905f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler
1291b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        // Watch for user changes
1292b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final IntentFilter userFilter = new IntentFilter();
1293b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        userFilter.addAction(Intent.ACTION_USER_ADDED);
1294b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        userFilter.addAction(Intent.ACTION_USER_REMOVED);
1295b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
1296b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1297b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        // Watch for USB changes on primary volume
1298b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume primary = getPrimaryPhysicalVolume();
1299b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (primary != null && primary.allowMassStorage()) {
1300b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            mContext.registerReceiver(
1301b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    mUsbReceiver, new IntentFilter(UsbManager.ACTION_USB_STATE), null, mHandler);
1302b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
1303b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1304a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        // Add OBB Action Handler to MountService thread.
1305a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());
1306a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1307c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen        /*
1308305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * Create the connection to vold with a maximum queue of twice the
1309305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * amount of containers we'd ever expect to have. This keeps an
1310305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * "asec list" from blocking a thread repeatedly.
1311305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         */
1312470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt        mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25);
131351a573c76737733638c475f52e441c814e6645ccKenny Root
1314305bcbf0c961840c4505770d084a1caacc074dbbKenny Root        Thread thread = new Thread(mConnector, VOLD_TAG);
1315207e538350665cea00e1aa70b8094beca4a34e45San Mehat        thread.start();
1316fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey
131707714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root        // Add ourself to the Watchdog monitors if enabled.
131807714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root        if (WATCHDOG_ENABLE) {
131907714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root            Watchdog.getInstance().addMonitor(this);
132007714d41e57ef9d8e2e6b40d8764e42053cce1bdKenny Root        }
1321207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
1322207e538350665cea00e1aa70b8094beca4a34e45San Mehat
1323b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    public void systemReady() {
1324b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mSystemReady = true;
1325b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
1326b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    }
1327b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1328207e538350665cea00e1aa70b8094beca4a34e45San Mehat    /**
13294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Exposed API calls below here
13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13317fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
13324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public void registerListener(IMountServiceListener listener) {
13334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
13344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            MountServiceBinderListener bl = new MountServiceBinderListener(listener);
13354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            try {
13364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                listener.asBinder().linkToDeath(bl, 0);
13374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListeners.add(bl);
13384270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } catch (RemoteException rex) {
1339a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to link to listener death");
13404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
13417fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public void unregisterListener(IMountServiceListener listener) {
13454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
13464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for(MountServiceBinderListener bl : mListeners) {
13474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                if (bl.mListener == listener) {
13484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(mListeners.indexOf(bl));
13495c25a2d338e9609d54e58cc1916c91cd8e9979abVairavan Srinivasan                    listener.asBinder().unlinkToDeath(bl, 0);
13504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    return;
13514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
13524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13566ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    public void shutdown(final IMountShutdownObserver observer) {
13574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.SHUTDOWN);
13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1359a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        Slog.i(TAG, "Shutting down");
1360b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
13617fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            for (String path : mVolumeStates.keySet()) {
13627fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                String state = mVolumeStates.get(path);
13637fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood
13647fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                if (state.equals(Environment.MEDIA_SHARED)) {
13657fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    /*
13667fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * If the media is currently shared, unshare it.
13677fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * XXX: This is still dangerous!. We should not
13687fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * be rebooting at *all* if UMS is enabled, since
13697fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * the UMS host could have dirty FAT cache entries
13707fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * yet to flush.
13717fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     */
13727fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    setUsbMassStorageEnabled(false);
13737fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                } else if (state.equals(Environment.MEDIA_CHECKING)) {
13747fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    /*
13757fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * If the media is being checked, then we need to wait for
13767fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * it to complete before being able to proceed.
13777fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     */
13787fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    // XXX: @hackbod - Should we disable the ANR timer here?
13797fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    int retries = 30;
13807fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
13817fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        try {
13827fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                            Thread.sleep(1000);
13837fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        } catch (InterruptedException iex) {
13847fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                            Slog.e(TAG, "Interrupted while waiting for media", iex);
13857fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                            break;
13867fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        }
13877fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        state = Environment.getExternalStorageState();
13887fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    }
13897fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    if (retries == 0) {
13907fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        Slog.e(TAG, "Timed out waiting for media to check");
13917fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    }
13924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
13937fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
13947fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                if (state.equals(Environment.MEDIA_MOUNTED)) {
13957fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    // Post a unmount message.
13967fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    ShutdownCallBack ucb = new ShutdownCallBack(path, observer);
13977fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
13987fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                } else if (observer != null) {
13997fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    /*
14007fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * Observer is waiting for onShutDownComplete when we are done.
14017fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * Since nothing will be done send notification directly so shutdown
14027fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     * sequence can continue.
14037fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                     */
14047fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    try {
14057fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        observer.onShutDownComplete(StorageResultCode.OperationSucceeded);
14067fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    } catch (RemoteException e) {
14077fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                        Slog.w(TAG, "RemoteException when shutting down");
14087fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                    }
14097fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                }
14105d0db4d356346bee68aec9a124df70dbaa9aaed1Johan Alfven            }
14111f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat        }
14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14140eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private boolean getUmsEnabling() {
14150eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        synchronized (mListeners) {
14160eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            return mUmsEnabling;
14170eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
14180eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
14190eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
14200eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private void setUmsEnabling(boolean enable) {
14210eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        synchronized (mListeners) {
1422fc71125104650c61ab5b04f4c943de761d58cba6Tony Wu            mUmsEnabling = enable;
14230eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
14240eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
14250eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
1426b104340496e3a531e26c8f428c808eca0e039f50San Mehat    public boolean isUsbMassStorageConnected() {
1427207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
14287fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
14290eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (getUmsEnabling()) {
1430b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return true;
1431b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
1432ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood        synchronized (mListeners) {
1433ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood            return mUmsAvailable;
1434ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood        }
14354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14370eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    public void setUsbMassStorageEnabled(boolean enable) {
1438207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
14390eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
14400eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
1441b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume primary = getPrimaryPhysicalVolume();
1442b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (primary == null) return;
1443b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
14440eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        // TODO: Add support for multiple share methods
1445b104340496e3a531e26c8f428c808eca0e039f50San Mehat
14460eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        /*
14470eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         * If the volume is mounted and we're enabling then unmount it
14480eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         */
1449b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        String path = primary.getPath();
14500eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        String vs = getVolumeState(path);
14510eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        String method = "ums";
14520eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
14530eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            // Override for isUsbMassStorageEnabled()
14540eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            setUmsEnabling(enable);
14550eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true);
14560eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb));
14570eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            // Clear override
14580eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            setUmsEnabling(false);
14590eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
14600eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        /*
14610eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         * If we disabled UMS then mount the volume
14620eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         */
14630eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (!enable) {
14640eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            doShareUnshareVolume(path, method, enable);
14650eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
1466a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to remount " + path +
14670eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                        " after disabling share method " + method);
14680eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                /*
14690eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * Even though the mount failed, the unshare didn't so don't indicate an error.
14700eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * The mountVolume() call will have set the storage state and sent the necessary
14710eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * broadcasts.
14720eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 */
14730eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            }
14740eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
14754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1477b104340496e3a531e26c8f428c808eca0e039f50San Mehat    public boolean isUsbMassStorageEnabled() {
1478207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1479b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
1480b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume primary = getPrimaryPhysicalVolume();
1481b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        if (primary != null) {
1482b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            return doGetVolumeShared(primary.getPath(), "ums");
1483b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        } else {
1484b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            return false;
1485b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        }
14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14879ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
14894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * @return state of the volume at the specified mount point
14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
14914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String getVolumeState(String mountPoint) {
1492b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
14937fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            String state = mVolumeStates.get(mountPoint);
14947fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            if (state == null) {
14957fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood                Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
149618db5c5690472f9da6ce2d580067307378675809Ken Sumrall                if (SystemProperties.get("vold.encrypt_progress").length() != 0) {
149718db5c5690472f9da6ce2d580067307378675809Ken Sumrall                    state = Environment.MEDIA_REMOVED;
149818db5c5690472f9da6ce2d580067307378675809Ken Sumrall                } else {
149918db5c5690472f9da6ce2d580067307378675809Ken Sumrall                    throw new IllegalArgumentException();
150018db5c5690472f9da6ce2d580067307378675809Ken Sumrall                }
15017fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            }
15024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
15037fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood            return state;
15047fa24aa8da3d2ab22b3a7d53fe64d14c31c076b8Mike Lockwood        }
15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1507b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    @Override
1508e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root    public boolean isExternalStorageEmulated() {
1509b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        return mEmulatedTemplate != null;
1510e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root    }
1511e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root
15124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int mountVolume(String path) {
15134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1515207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1516207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return doMountVolume(path);
15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
151913c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo    public void unmountVolume(String path, boolean force, boolean removeEncryption) {
15204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1521207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15238a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        String volState = getVolumeState(path);
152413c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo        if (DEBUG_UNMOUNT) {
152513c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo            Slog.i(TAG, "Unmounting " + path
152613c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo                    + " force = " + force
152713c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo                    + " removeEncryption = " + removeEncryption);
152813c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo        }
15298a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        if (Environment.MEDIA_UNMOUNTED.equals(volState) ||
15308a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_REMOVED.equals(volState) ||
15318a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_SHARED.equals(volState) ||
15328a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_UNMOUNTABLE.equals(volState)) {
15338a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            // Media already unmounted or cannot be unmounted.
15348a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            // TODO return valid return code when adding observer call back.
15358a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            return;
15368a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
153713c7197da8a16f77f6398708a6314c80cb01e0d1Ben Komalo        UnmountCallBack ucb = new UnmountCallBack(path, force, removeEncryption);
1538c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
15394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int formatVolume(String path) {
15424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1543207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1545207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return doFormatVolume(path);
15469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15473697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1548ecedfdc7794048cd539e3df92b641a18a05acdf7Mike Lockwood    public int[] getStorageUsers(String path) {
1549c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1550c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        waitForReady();
1551c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        try {
1552dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            final String[] r = NativeDaemonEvent.filterMessageList(
1553dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                    mConnector.executeForList("storage", "users", path),
1554dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                    VoldResponseCode.StorageUsersListResult);
1555dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey
1556c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            // FMT: <pid> <process name>
1557c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            int[] data = new int[r.length];
1558c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            for (int i = 0; i < r.length; i++) {
1559dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                String[] tok = r[i].split(" ");
1560c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                try {
1561c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                    data[i] = Integer.parseInt(tok[0]);
1562c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                } catch (NumberFormatException nfe) {
1563a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
1564c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                    return new int[0];
1565c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                }
1566c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            }
1567c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            return data;
1568c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        } catch (NativeDaemonConnectorException e) {
1569a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Failed to retrieve storage users list", e);
1570c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            return new int[0];
1571c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        }
1572c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat    }
1573c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat
1574b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private void warnOnNotMounted() {
1575b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final StorageVolume primary = getPrimaryPhysicalVolume();
157632ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey        if (primary != null) {
157732ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey            boolean mounted = false;
157832ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey            try {
157932ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey                mounted = Environment.MEDIA_MOUNTED.equals(getVolumeState(primary.getPath()));
158032ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey            } catch (IllegalStateException e) {
158132ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey            }
158232ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey
158332ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey            if (!mounted) {
158432ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey                Slog.w(TAG, "getSecureContainerList() called when storage not mounted");
158532ee831eabc43001d756897e57f52f527bd9c431Jeff Sharkey            }
1586b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
1587b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
1588b104340496e3a531e26c8f428c808eca0e039f50San Mehat
15894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String[] getSecureContainerList() {
15904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
1591207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1592b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1593f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
15944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1595dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return NativeDaemonEvent.filterMessageList(
1596dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                    mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
15974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
15984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            return new String[0];
159902735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
16003697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
16013697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
16026dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root    public int createSecureContainer(String id, int sizeMb, String fstype, String key,
16036dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root            int ownerUid, boolean external) {
16044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_CREATE);
1605207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1606b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
16074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1608b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
16094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
16106dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root            mConnector.execute("asec", "create", id, sizeMb, fstype, key, ownerUid,
16116dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root                    external ? "1" : "0");
16124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1613b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
161402735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1615a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1616a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        if (rc == StorageResultCode.OperationSucceeded) {
1617a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            synchronized (mAsecMountSet) {
1618a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                mAsecMountSet.add(id);
1619a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1620a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
16214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
16223697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
16233697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
16244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int finalizeSecureContainer(String id) {
16254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_CREATE);
1626b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
16274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1628b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
16294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1630dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("asec", "finalize", id);
1631a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            /*
1632a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             * Finalization does a remount, so no need
1633a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             * to update mAsecMountSet
1634a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             */
16356dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        } catch (NativeDaemonConnectorException e) {
16366dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root            rc = StorageResultCode.OperationFailedInternalError;
16376dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        }
16386dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        return rc;
16396dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root    }
16406dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root
16416dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root    public int fixPermissionsSecureContainer(String id, int gid, String filename) {
16426dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        validatePermission(android.Manifest.permission.ASEC_CREATE);
16436dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        warnOnNotMounted();
16446dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root
16456dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        int rc = StorageResultCode.OperationSucceeded;
16466dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root        try {
16476dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root            mConnector.execute("asec", "fixperms", id, gid, filename);
16486dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root            /*
16496dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root             * Fix permissions does a remount, so no need to update
16506dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root             * mAsecMountSet
16516dceb88f1c7c42c6ab43834af2c993d599895d82Kenny Root             */
16524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1653b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
165402735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
16554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
16563697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
16573697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1658d970998b0d489774ad1c5b94b47d233912f00214San Mehat    public int destroySecureContainer(String id, boolean force) {
16594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_DESTROY);
1660207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1661b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1662f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
1663aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
1664aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
1665aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
1666aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
1667aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
1668aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
1669aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
1670aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
1671b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
16724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1673dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            final Command cmd = new Command("asec", "destroy", id);
1674dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            if (force) {
1675dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                cmd.appendArg("force");
1676dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            }
1677dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute(cmd);
16784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1679d970998b0d489774ad1c5b94b47d233912f00214San Mehat            int code = e.getCode();
1680d970998b0d489774ad1c5b94b47d233912f00214San Mehat            if (code == VoldResponseCode.OpFailedStorageBusy) {
1681d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedStorageBusy;
1682d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else {
1683d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedInternalError;
1684d970998b0d489774ad1c5b94b47d233912f00214San Mehat            }
168502735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1686a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1687a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        if (rc == StorageResultCode.OperationSucceeded) {
1688a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            synchronized (mAsecMountSet) {
1689a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                if (mAsecMountSet.contains(id)) {
1690a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                    mAsecMountSet.remove(id);
1691a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                }
1692a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1693a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1694a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
16954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
16963697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
16979ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
16984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int mountSecureContainer(String id, String key, int ownerUid) {
16994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
1700207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1701b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
17024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1703a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        synchronized (mAsecMountSet) {
1704a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            if (mAsecMountSet.contains(id)) {
1705a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageMounted;
1706a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1707a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1708a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1709b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
17104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1711dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("asec", "mount", id, key, ownerUid);
17124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1713f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            int code = e.getCode();
1714f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            if (code != VoldResponseCode.OpFailedStorageBusy) {
1715f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root                rc = StorageResultCode.OperationFailedInternalError;
1716f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            }
171702735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
17186cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
17196cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        if (rc == StorageResultCode.OperationSucceeded) {
17206cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            synchronized (mAsecMountSet) {
17216cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat                mAsecMountSet.add(id);
17226cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
17236cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
17244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
17253697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
17263697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1727d970998b0d489774ad1c5b94b47d233912f00214San Mehat    public int unmountSecureContainer(String id, boolean force) {
17284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
1729207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1730b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
17314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
17326cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        synchronized (mAsecMountSet) {
17336cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            if (!mAsecMountSet.contains(id)) {
1734a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageNotMounted;
17356cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
17366cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat         }
17376cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
1738aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
1739aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
1740aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
1741aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
1742aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
1743aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
1744aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
1745aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
1746b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
17474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1748dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            final Command cmd = new Command("asec", "unmount", id);
1749dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            if (force) {
1750dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                cmd.appendArg("force");
1751dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            }
1752dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute(cmd);
17534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1754d970998b0d489774ad1c5b94b47d233912f00214San Mehat            int code = e.getCode();
1755d970998b0d489774ad1c5b94b47d233912f00214San Mehat            if (code == VoldResponseCode.OpFailedStorageBusy) {
1756d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedStorageBusy;
1757d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else {
1758d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedInternalError;
1759d970998b0d489774ad1c5b94b47d233912f00214San Mehat            }
176002735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
17616cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
17626cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        if (rc == StorageResultCode.OperationSucceeded) {
17636cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            synchronized (mAsecMountSet) {
17646cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat                mAsecMountSet.remove(id);
17656cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
17666cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
17674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
17689dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat    }
17699dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat
17706cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    public boolean isSecureContainerMounted(String id) {
17716cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
17726cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        waitForReady();
17736cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        warnOnNotMounted();
17746cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
17756cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        synchronized (mAsecMountSet) {
17766cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            return mAsecMountSet.contains(id);
17776cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
17786cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    }
17796cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
17804270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int renameSecureContainer(String oldId, String newId) {
17814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_RENAME);
1782207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1783b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
17844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1785a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        synchronized (mAsecMountSet) {
178685451ee15fdf6cae371dc3005441988c7d426401San Mehat            /*
17879ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks             * Because a mounted container has active internal state which cannot be
178885451ee15fdf6cae371dc3005441988c7d426401San Mehat             * changed while active, we must ensure both ids are not currently mounted.
178985451ee15fdf6cae371dc3005441988c7d426401San Mehat             */
179085451ee15fdf6cae371dc3005441988c7d426401San Mehat            if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
1791a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageMounted;
1792a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1793a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1794a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1795b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
17964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1797dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("asec", "rename", oldId, newId);
17984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1799b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
180002735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1801a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
18024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
180345f61040823d8c442838f75cde8760f236603daeSan Mehat    }
180445f61040823d8c442838f75cde8760f236603daeSan Mehat
18054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String getSecureContainerPath(String id) {
18064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
1807207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1808b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1809f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
1810dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
18112d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        try {
1812dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("asec", "path", id);
1813dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event.checkCode(VoldResponseCode.AsecPathResult);
1814dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return event.getMessage();
18152d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        } catch (NativeDaemonConnectorException e) {
18162d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            int code = e.getCode();
18172d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            if (code == VoldResponseCode.OpFailedStorageNotFound) {
1818a20c8ef471666cf8b0dca91a8739ff18af1741a5Fredrik Helmer                Slog.i(TAG, String.format("Container '%s' not found", id));
1819a20c8ef471666cf8b0dca91a8739ff18af1741a5Fredrik Helmer                return null;
182022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            } else {
18212d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat                throw new IllegalStateException(String.format("Unexpected response code %d", code));
182222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            }
182322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
182422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
1825292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn
1826292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn    public String getSecureContainerFilesystemPath(String id) {
1827292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        validatePermission(android.Manifest.permission.ASEC_ACCESS);
1828292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        waitForReady();
1829292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        warnOnNotMounted();
1830292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn
1831dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
1832292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        try {
1833dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("asec", "fspath", id);
1834dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event.checkCode(VoldResponseCode.AsecPathResult);
1835dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return event.getMessage();
1836292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        } catch (NativeDaemonConnectorException e) {
1837292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn            int code = e.getCode();
1838292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn            if (code == VoldResponseCode.OpFailedStorageNotFound) {
1839292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn                Slog.i(TAG, String.format("Container '%s' not found", id));
1840292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn                return null;
1841292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn            } else {
1842292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn                throw new IllegalStateException(String.format("Unexpected response code %d", code));
1843292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn            }
1844292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn        }
1845292f8bc9d1b790ab975a87a842c7fabc908b97e0Dianne Hackborn    }
1846e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu
1847e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu    public void finishMediaUpdate() {
1848e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
1849e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu    }
185002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1851a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
1852a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        if (callerUid == android.os.Process.SYSTEM_UID) {
1853a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return true;
1854a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1855a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
185602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        if (packageName == null) {
185702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            return false;
185802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
185902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1860f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        final int packageUid = mPms.getPackageUid(packageName, UserHandle.getUserId(callerUid));
186102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
186202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        if (DEBUG_OBB) {
186302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
186402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root                    packageUid + ", callerUid = " + callerUid);
186502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
186602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
186702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        return callerUid == packageUid;
186802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
186902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
18704fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    public String getMountedObbPath(String rawPath) {
18714fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
1872af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
187302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        waitForReady();
187402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        warnOnNotMounted();
187502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
18764fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final ObbState state;
18774fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        synchronized (mObbPathToStateMap) {
18784fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            state = mObbPathToStateMap.get(rawPath);
18794fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        }
18804fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        if (state == null) {
18814fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            Slog.w(TAG, "Failed to find OBB mounted at " + rawPath);
18824fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            return null;
18834fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        }
18844fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
1885dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
188602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        try {
18874fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            event = mConnector.execute("obb", "path", state.voldPath);
1888dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event.checkCode(VoldResponseCode.AsecPathResult);
1889dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return event.getMessage();
189002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        } catch (NativeDaemonConnectorException e) {
189102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            int code = e.getCode();
189202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            if (code == VoldResponseCode.OpFailedStorageNotFound) {
1893a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                return null;
189402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            } else {
189502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root                throw new IllegalStateException(String.format("Unexpected response code %d", code));
189602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
189702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
189802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
189902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
19004fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    @Override
19014fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    public boolean isObbMounted(String rawPath) {
19024fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
1903a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        synchronized (mObbMounts) {
19044fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            return mObbPathToStateMap.containsKey(rawPath);
1905a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1906a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
1907a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
19084fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    @Override
19094fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    public void mountObb(
19104fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) {
19114fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
19124fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
19134fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        Preconditions.checkNotNull(token, "token cannot be null");
19144fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
19154fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final int callingUid = Binder.getCallingUid();
19164fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce);
19174fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final ObbAction action = new MountObbAction(obbState, key, callingUid);
1918a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
1919a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1920a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        if (DEBUG_OBB)
1921a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            Slog.i(TAG, "Send to OBB handler: " + action.toString());
192202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
192302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
19244fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    @Override
19254fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
19264fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
19274fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
19284fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final ObbState existingState;
19294fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        synchronized (mObbPathToStateMap) {
19304fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            existingState = mObbPathToStateMap.get(rawPath);
1931f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root        }
1932f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root
19334fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        if (existingState != null) {
19344fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            // TODO: separate state object from request data
19354fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            final int callingUid = Binder.getCallingUid();
19364fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            final ObbState newState = new ObbState(
19374fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                    rawPath, existingState.canonicalPath, callingUid, token, nonce);
19384fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            final ObbAction action = new UnmountObbAction(newState, force);
19394fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
1940a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
19414fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            if (DEBUG_OBB)
19424fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                Slog.i(TAG, "Send to OBB handler: " + action.toString());
19434fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        } else {
19444fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            Slog.w(TAG, "Unknown OBB mount at " + rawPath);
19454fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        }
1946a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
194702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1948444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo    @Override
1949444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo    public int getEncryptionState() {
1950444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
1951444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo                "no permission to access the crypt keeper");
1952444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo
1953444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        waitForReady();
1954444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo
1955dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
1956444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        try {
1957dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("cryptfs", "cryptocomplete");
1958dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return Integer.parseInt(event.getMessage());
1959444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        } catch (NumberFormatException e) {
1960444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            // Bad result - unexpected.
1961444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
1962444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            return ENCRYPTION_STATE_ERROR_UNKNOWN;
1963444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        } catch (NativeDaemonConnectorException e) {
1964444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            // Something bad happened.
1965444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            Slog.w(TAG, "Error in communicating with cryptfs in validating");
1966444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo            return ENCRYPTION_STATE_ERROR_UNKNOWN;
1967444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        }
1968444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo    }
1969444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo
1970444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo    @Override
19715af0b916f850486cff4797355bf9e7dc3352fe00Jason parks    public int decryptStorage(String password) {
1972f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (TextUtils.isEmpty(password)) {
1973f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            throw new IllegalArgumentException("password cannot be empty");
19745af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        }
19755af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
19768888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
19778888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks                "no permission to access the crypt keeper");
19785af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
19795af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        waitForReady();
19805af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
19815af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        if (DEBUG_EVENTS) {
19825af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            Slog.i(TAG, "decrypting storage...");
19835af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        }
19845af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
1985dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
19865af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        try {
1987dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("cryptfs", "checkpw", password);
19889ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
1989da6aedf716bfdd40148823fb63d666d34b7b425eFredrik Roubert            final int code = Integer.parseInt(event.getMessage());
19909ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            if (code == 0) {
19919ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                // Decrypt was successful. Post a delayed message before restarting in order
19929ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                // to let the UI to clear itself
19939ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                mHandler.postDelayed(new Runnable() {
19949ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                    public void run() {
199531c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey                        try {
1996dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                            mConnector.execute("cryptfs", "restart");
199731c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey                        } catch (NativeDaemonConnectorException e) {
199831c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey                            Slog.e(TAG, "problem executing in background", e);
199931c6e4817f6c967fc4f61c4f1d9f25743958f7deJeff Sharkey                        }
20009ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                    }
2001f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks                }, 1000); // 1 second
20029ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            }
20039ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
20049ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            return code;
20055af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        } catch (NativeDaemonConnectorException e) {
20065af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            // Decryption failed
20075af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            return e.getCode();
20085af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        }
20095af0b916f850486cff4797355bf9e7dc3352fe00Jason parks    }
20105af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
201156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks    public int encryptStorage(String password) {
2012f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (TextUtils.isEmpty(password)) {
2013f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            throw new IllegalArgumentException("password cannot be empty");
201456aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        }
201556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
20168888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
20178888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks            "no permission to access the crypt keeper");
201856aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
201956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        waitForReady();
202056aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
202156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        if (DEBUG_EVENTS) {
20228888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks            Slog.i(TAG, "encrypting storage...");
202356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        }
202456aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
202556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        try {
2026dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            mConnector.execute("cryptfs", "enablecrypto", "inplace", password);
202756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        } catch (NativeDaemonConnectorException e) {
202856aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks            // Encryption failed
202956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks            return e.getCode();
203056aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        }
203156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
203256aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        return 0;
203356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks    }
203456aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
2035f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks    public int changeEncryptionPassword(String password) {
2036f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (TextUtils.isEmpty(password)) {
2037f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            throw new IllegalArgumentException("password cannot be empty");
2038f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        }
2039f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
2040f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2041f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            "no permission to access the crypt keeper");
2042f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
2043f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        waitForReady();
2044f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
2045f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (DEBUG_EVENTS) {
2046f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            Slog.i(TAG, "changing encryption password...");
2047f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        }
2048f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
2049dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
2050f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        try {
2051dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("cryptfs", "changepw", password);
2052dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return Integer.parseInt(event.getMessage());
2053f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        } catch (NativeDaemonConnectorException e) {
2054f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            // Encryption failed
2055f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            return e.getCode();
2056f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        }
2057f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks    }
2058f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
205932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate    /**
206032418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate     * Validate a user-supplied password string with cryptfs
206132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate     */
206232418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate    @Override
206332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate    public int verifyEncryptionPassword(String password) throws RemoteException {
206432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        // Only the system process is permitted to validate passwords
206532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
206632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            throw new SecurityException("no permission to access the crypt keeper");
206732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        }
206832418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
206932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
207032418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            "no permission to access the crypt keeper");
207132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
207232418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        if (TextUtils.isEmpty(password)) {
207332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            throw new IllegalArgumentException("password cannot be empty");
207432418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        }
207532418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
207632418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        waitForReady();
207732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
207832418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        if (DEBUG_EVENTS) {
207932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            Slog.i(TAG, "validating encryption password...");
208032418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        }
208132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
2082dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey        final NativeDaemonEvent event;
208332418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        try {
2084dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            event = mConnector.execute("cryptfs", "verifypw", password);
2085dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
2086dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey            return Integer.parseInt(event.getMessage());
208732418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        } catch (NativeDaemonConnectorException e) {
208832418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            // Encryption failed
208932418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate            return e.getCode();
209032418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate        }
209132418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate    }
209232418be49e5b61c2e9281528cb8fb67939e301e8Christopher Tate
2093b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    @Override
2094b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey    public StorageVolume[] getVolumeList() {
2095b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final int callingUserId = UserHandle.getCallingUserId();
2096b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        final boolean accessAll = (mContext.checkPermission(
2097b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                android.Manifest.permission.ACCESS_ALL_EXTERNAL_STORAGE,
2098b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                Binder.getCallingPid(), Binder.getCallingUid()) == PERMISSION_GRANTED);
2099b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey
2100b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
2101b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            final ArrayList<StorageVolume> filtered = Lists.newArrayList();
2102b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            for (StorageVolume volume : mVolumes) {
2103b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                final UserHandle owner = volume.getOwner();
2104b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                final boolean ownerMatch = owner == null || owner.getIdentifier() == callingUserId;
2105b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                if (accessAll || ownerMatch) {
2106b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                    filtered.add(volume);
2107b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey                }
21088fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood            }
2109b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey            return filtered.toArray(new StorageVolume[filtered.size()]);
21108fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood        }
21118fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood    }
21128fa5f804e21233c5f1993212fd5fb7c200eec905Mike Lockwood
2113af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private void addObbStateLocked(ObbState obbState) throws RemoteException {
2114af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IBinder binder = obbState.getBinder();
2115af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        List<ObbState> obbStates = mObbMounts.get(binder);
21165919ac6b4188285324646772501ef4b97b353cf4Kenny Root
2117af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (obbStates == null) {
2118af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbStates = new ArrayList<ObbState>();
2119af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            mObbMounts.put(binder, obbStates);
2120af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        } else {
2121af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            for (final ObbState o : obbStates) {
21224fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                if (o.rawPath.equals(obbState.rawPath)) {
2123af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    throw new IllegalStateException("Attempt to add ObbState twice. "
2124af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            + "This indicates an error in the MountService logic.");
21255919ac6b4188285324646772501ef4b97b353cf4Kenny Root                }
21265919ac6b4188285324646772501ef4b97b353cf4Kenny Root            }
212702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
212802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2129af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        obbStates.add(obbState);
2130af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        try {
2131af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbState.link();
2132af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        } catch (RemoteException e) {
2133af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            /*
2134af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * The binder died before we could link it, so clean up our state
2135af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * and return failure.
2136af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             */
2137af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbStates.remove(obbState);
2138af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.isEmpty()) {
2139af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mObbMounts.remove(binder);
214005105f7abe02b2dff91d6260b3628c8b97816babKenny Root            }
21415919ac6b4188285324646772501ef4b97b353cf4Kenny Root
2142af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            // Rethrow the error so mountObb can get it
2143af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw e;
214402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
2145af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
21464fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        mObbPathToStateMap.put(obbState.rawPath, obbState);
2147a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
214802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2149af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private void removeObbStateLocked(ObbState obbState) {
2150af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IBinder binder = obbState.getBinder();
2151af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final List<ObbState> obbStates = mObbMounts.get(binder);
2152af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (obbStates != null) {
2153af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.remove(obbState)) {
2154af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                obbState.unlink();
2155af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2156af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.isEmpty()) {
2157af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mObbMounts.remove(binder);
2158af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
215938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
2160af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
21614fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        mObbPathToStateMap.remove(obbState.rawPath);
216238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    }
216338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2164a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private class ObbActionHandler extends Handler {
2165a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private boolean mBound = false;
2166480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root        private final List<ObbAction> mActions = new LinkedList<ObbAction>();
2167a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2168a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbActionHandler(Looper l) {
2169a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(l);
2170a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2171a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2172a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
2173a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleMessage(Message msg) {
2174a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            switch (msg.what) {
2175a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_RUN_ACTION: {
2176480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                    final ObbAction action = (ObbAction) msg.obj;
2177a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2178a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
2179a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
2180a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2181a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // If a bind was already initiated we don't really
2182a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // need to do anything. The pending install
2183a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // will be processed later on.
2184a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (!mBound) {
2185a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // If this is the only one pending we might
2186a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // have to bind to the service again.
2187a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (!connectToService()) {
2188a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            Slog.e(TAG, "Failed to bind to media container service");
2189a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.handleError();
2190a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            return;
2191a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2192a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2193735de3b38abbd6564082a819377673ee593744a6Kenny Root
2194735de3b38abbd6564082a819377673ee593744a6Kenny Root                    mActions.add(action);
2195a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
2196a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2197a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_BOUND: {
2198a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
2199a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_BOUND");
2200a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (msg.obj != null) {
2201a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mContainerService = (IMediaContainerService) msg.obj;
2202a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2203a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mContainerService == null) {
2204a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Something seriously wrong. Bail out
2205a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.e(TAG, "Cannot bind to media container service");
2206a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        for (ObbAction action : mActions) {
2207a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            // Indicate service bind error
2208a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.handleError();
2209a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2210a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mActions.clear();
2211a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else if (mActions.size() > 0) {
2212480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                        final ObbAction action = mActions.get(0);
2213a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (action != null) {
2214a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.execute(this);
2215a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2216a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else {
2217a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Should never happen ideally.
2218a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.w(TAG, "Empty queue");
2219a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2220a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
2221a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2222a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_RECONNECT: {
2223a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
2224a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_RECONNECT");
2225a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() > 0) {
2226a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (mBound) {
2227a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            disconnectService();
2228a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2229a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (!connectToService()) {
2230a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            Slog.e(TAG, "Failed to bind to media container service");
2231a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            for (ObbAction action : mActions) {
2232a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                                // Indicate service bind error
2233a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                                action.handleError();
2234a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            }
2235a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            mActions.clear();
2236a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2237a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2238a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
2239a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2240a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_UNBIND: {
2241a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
2242a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_UNBIND");
2243a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2244a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // Delete pending install
2245a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() > 0) {
2246a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mActions.remove(0);
2247a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2248a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() == 0) {
2249a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (mBound) {
2250a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            disconnectService();
2251a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
2252a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else {
2253a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // There are more pending requests in queue.
2254a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Just post MCS_BOUND message to trigger processing
2255a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // of next pending install.
2256a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
2257a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
2258a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
2259a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2260af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                case OBB_FLUSH_MOUNT_STATE: {
2261af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    final String path = (String) msg.obj;
2262af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2263af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    if (DEBUG_OBB)
2264af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        Slog.i(TAG, "Flushing all OBB state for path " + path);
2265af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2266af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    synchronized (mObbMounts) {
2267af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
2268af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
22694fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                        final Iterator<ObbState> i = mObbPathToStateMap.values().iterator();
2270af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        while (i.hasNext()) {
22714fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                            final ObbState state = i.next();
2272af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2273af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            /*
2274af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * If this entry's source file is in the volume path
2275af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * that got unmounted, remove it because it's no
2276af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * longer valid.
2277af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             */
22784fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                            if (state.canonicalPath.startsWith(path)) {
22794fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                                obbStatesToRemove.add(state);
2280af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            }
2281af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        }
2282af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2283af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        for (final ObbState obbState : obbStatesToRemove) {
2284af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            if (DEBUG_OBB)
22854fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                                Slog.i(TAG, "Removing state for " + obbState.rawPath);
2286af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2287af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            removeObbStateLocked(obbState);
2288af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2289af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            try {
22904fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                                obbState.token.onObbResult(obbState.rawPath, obbState.nonce,
2291af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                        OnObbStateChangeListener.UNMOUNTED);
2292af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            } catch (RemoteException e) {
2293af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                Slog.i(TAG, "Couldn't send unmount notification for  OBB: "
22944fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                                        + obbState.rawPath);
2295af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            }
2296af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        }
2297af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    }
2298af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    break;
2299af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                }
230002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
230102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
230202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2303a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private boolean connectToService() {
2304a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
2305a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "Trying to bind to DefaultContainerService");
2306a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2307a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
2308a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) {
2309a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mBound = true;
2310a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                return true;
231102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
2312a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return false;
2313a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2314a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2315a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private void disconnectService() {
2316a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mContainerService = null;
2317a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mBound = false;
2318a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mContext.unbindService(mDefContainerConn);
231902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
232002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
232102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2322a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    abstract class ObbAction {
2323a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private static final int MAX_RETRIES = 3;
2324a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private int mRetries;
232502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2326a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbState mObbState;
2327a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2328a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbAction(ObbState obbState) {
2329a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbState = obbState;
233002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
233102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
2332a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void execute(ObbActionHandler handler) {
2333a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            try {
2334a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
2335444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo                    Slog.i(TAG, "Starting to execute action: " + toString());
2336a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mRetries++;
2337a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (mRetries > MAX_RETRIES) {
2338a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
2339480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                    mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
2340a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    handleError();
2341a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    return;
2342a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                } else {
2343a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    handleExecute();
2344a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
2345a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "Posting install MCS_UNBIND");
2346a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
2347a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2348a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            } catch (RemoteException e) {
2349a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
2350a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.i(TAG, "Posting install MCS_RECONNECT");
2351a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
2352a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            } catch (Exception e) {
2353a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
2354a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.d(TAG, "Error handling OBB action", e);
2355a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                handleError();
235617eb6fb07cc6965f09c51adc70b3c291f57a784aKenny Root                mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
235702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
2358a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
235902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
236005105f7abe02b2dff91d6260b3628c8b97816babKenny Root        abstract void handleExecute() throws RemoteException, IOException;
2361a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        abstract void handleError();
236238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
236338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        protected ObbInfo getObbInfo() throws IOException {
236438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            ObbInfo obbInfo;
236538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            try {
23664fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                obbInfo = mContainerService.getObbInfo(mObbState.ownerPath);
236738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } catch (RemoteException e) {
236838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
23694fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                        + mObbState.ownerPath);
237038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                obbInfo = null;
237138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
237238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            if (obbInfo == null) {
23734fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                throw new IOException("Couldn't read OBB file: " + mObbState.ownerPath);
237438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
237538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return obbInfo;
237638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
237738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2378af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        protected void sendNewStatusOrIgnore(int status) {
2379af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (mObbState == null || mObbState.token == null) {
2380af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2381af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2382af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
238338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            try {
23844fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
238538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } catch (RemoteException e) {
238638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
238738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
238838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
2389a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
2390a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2391a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class MountObbAction extends ObbAction {
2392444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        private final String mKey;
23934fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        private final int mCallingUid;
2394a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
23954fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        MountObbAction(ObbState obbState, String key, int callingUid) {
2396a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(obbState);
2397a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mKey = key;
23984fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            mCallingUid = callingUid;
2399a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2400a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
24015af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
2402735de3b38abbd6564082a819377673ee593744a6Kenny Root        public void handleExecute() throws IOException, RemoteException {
2403af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            waitForReady();
2404af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            warnOnNotMounted();
2405af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
240638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            final ObbInfo obbInfo = getObbInfo();
240738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
24084fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
2409af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
2410af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        + " which is owned by " + obbInfo.packageName);
2411af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
2412af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2413af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2414af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2415af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final boolean isMounted;
2416af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            synchronized (mObbMounts) {
24174fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
2418af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2419af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (isMounted) {
2420af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
2421af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
2422af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2423af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2424af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2425af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final String hashedKey;
2426af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (mKey == null) {
2427af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                hashedKey = "none";
2428af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } else {
2429af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                try {
24303b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
24313b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
24323b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
24333b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                            PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
24343b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    SecretKey key = factory.generateSecret(ks);
24353b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    BigInteger bi = new BigInteger(key.getEncoded());
24363b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    hashedKey = bi.toString(16);
2437af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } catch (NoSuchAlgorithmException e) {
24383b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
24393b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
24403b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    return;
24413b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                } catch (InvalidKeySpecException e) {
24423b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
24433b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
2444af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    return;
244538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                }
2446a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
2447a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2448af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            int rc = StorageResultCode.OperationSucceeded;
2449af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            try {
2450dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                mConnector.execute(
24514fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                        "obb", "mount", mObbState.voldPath, hashedKey, mObbState.ownerGid);
2452af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } catch (NativeDaemonConnectorException e) {
2453af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                int code = e.getCode();
2454af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (code != VoldResponseCode.OpFailedStorageBusy) {
2455af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedInternalError;
2456a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2457af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2458a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2459af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (rc == StorageResultCode.OperationSucceeded) {
2460af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (DEBUG_OBB)
24614fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                    Slog.d(TAG, "Successfully mounted OBB " + mObbState.voldPath);
246238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2463af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                synchronized (mObbMounts) {
2464af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    addObbStateLocked(mObbState);
2465a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
246638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2467af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
246802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            } else {
246905105f7abe02b2dff91d6260b3628c8b97816babKenny Root                Slog.e(TAG, "Couldn't mount OBB file: " + rc);
2470a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2471af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
247202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
247302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
247402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
24755af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
2476a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleError() {
2477af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
247802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
2479a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2480a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
2481a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public String toString() {
2482a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            StringBuilder sb = new StringBuilder();
2483a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("MountObbAction{");
24844fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append(mObbState);
2485a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append('}');
2486a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return sb.toString();
2487a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2488a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
2489a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2490a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class UnmountObbAction extends ObbAction {
2491444eca232964dbf27d0c4d01447c1493f89186e0Ben Komalo        private final boolean mForceUnmount;
2492a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2493a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        UnmountObbAction(ObbState obbState, boolean force) {
2494a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(obbState);
2495a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mForceUnmount = force;
2496a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2497a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
24985af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
249938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        public void handleExecute() throws IOException {
2500af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            waitForReady();
2501af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            warnOnNotMounted();
2502af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
250338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            final ObbInfo obbInfo = getObbInfo();
2504a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
25054fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            final ObbState existingState;
250638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            synchronized (mObbMounts) {
25074fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                existingState = mObbPathToStateMap.get(mObbState.rawPath);
2508af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
250938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
25104fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            if (existingState == null) {
2511af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
2512af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2513a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
2514a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
25154fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            if (existingState.ownerGid != mObbState.ownerGid) {
25164fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
25174fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                        + " (owned by GID " + existingState.ownerGid + ")");
2518af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
2519af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2520af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2521a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2522af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            int rc = StorageResultCode.OperationSucceeded;
2523af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            try {
25244fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                final Command cmd = new Command("obb", "unmount", mObbState.voldPath);
2525dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                if (mForceUnmount) {
2526dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                    cmd.appendArg("force");
2527dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                }
2528dd519fac9b79f36a27909149a90fce4321ed1c20Jeff Sharkey                mConnector.execute(cmd);
2529af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } catch (NativeDaemonConnectorException e) {
2530af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                int code = e.getCode();
2531af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (code == VoldResponseCode.OpFailedStorageBusy) {
2532af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedStorageBusy;
2533af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
2534af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    // If it's not mounted then we've already won.
2535af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationSucceeded;
2536af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } else {
2537af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedInternalError;
2538a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2539a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
254038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2541af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (rc == StorageResultCode.OperationSucceeded) {
2542af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                synchronized (mObbMounts) {
25434fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                    removeObbStateLocked(existingState);
2544af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                }
254538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2546af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
254738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } else {
25484fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                Slog.w(TAG, "Could not unmount OBB: " + existingState);
2549af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
255038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
2551a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2552a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
25535af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
2554a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleError() {
2555af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
2556a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2557a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2558a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
2559a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public String toString() {
2560a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            StringBuilder sb = new StringBuilder();
2561a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("UnmountObbAction{");
25624fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            sb.append(mObbState);
2563a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",force=");
2564a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mForceUnmount);
2565a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append('}');
2566a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return sb.toString();
2567a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
256802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
256938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
25708b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey    @VisibleForTesting
25714fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    public static String buildObbPath(final String canonicalPath, int userId, boolean forVold) {
25724fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        // TODO: allow caller to provide Environment for full testing
25734fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
25744fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        // Only adjust paths when storage is emulated
25754fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        if (!Environment.isExternalStorageEmulated()) {
25764fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            return canonicalPath;
25774fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        }
25784fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
25794fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        String path = canonicalPath.toString();
25804fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
25814fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        // First trim off any external storage prefix
25824fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final UserEnvironment userEnv = new UserEnvironment(userId);
25834fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
25844fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        // /storage/emulated/0
25854fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final String externalPath = userEnv.getExternalStorageDirectory().toString();
25864fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        // /storage/emulated_legacy
25874fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final String legacyExternalPath = Environment.getLegacyExternalStorageDirectory()
25884fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                .toString();
25894fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
25904fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        if (path.startsWith(externalPath)) {
25914fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            path = path.substring(externalPath.length() + 1);
25924fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        } else if (path.startsWith(legacyExternalPath)) {
25934fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            path = path.substring(legacyExternalPath.length() + 1);
25944fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        } else {
25954fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            return canonicalPath;
25964fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        }
25974fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
25984fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        // Handle special OBB paths on emulated storage
25994fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        final String obbPath = "Android/obb";
26004fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        if (path.startsWith(obbPath)) {
26014fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            path = path.substring(obbPath.length() + 1);
26024fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
26034fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            if (forVold) {
26044fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                return new File(Environment.getEmulatedStorageObbSource(), path).toString();
26054fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            } else {
26064fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                final UserEnvironment ownerEnv = new UserEnvironment(UserHandle.USER_OWNER);
26074fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey                return new File(ownerEnv.getExternalStorageObbDirectory(), path).toString();
26084fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            }
26094fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        }
26104fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
26114fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        // Handle normal external storage paths
26124fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        if (forVold) {
26134fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            return new File(Environment.getEmulatedStorageSource(userId), path).toString();
26144fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        } else {
26154fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey            return new File(userEnv.getExternalStorageDirectory(), path).toString();
26164fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey        }
26174fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey    }
26184fbbda4cecb078bd3867f416b02cc75f5455284fJeff Sharkey
261938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    @Override
262038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
262138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
262238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            pw.println("Permission Denial: can't dump ActivityManager from from pid="
262338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
262438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                    + " without permission " + android.Manifest.permission.DUMP);
262538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return;
262638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
262738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
262838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        synchronized (mObbMounts) {
2629af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("  mObbMounts:");
263038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2631af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet().iterator();
2632af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            while (binders.hasNext()) {
2633af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Entry<IBinder, List<ObbState>> e = binders.next();
2634af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print("    Key="); pw.println(e.getKey().toString());
2635af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                final List<ObbState> obbStates = e.getValue();
263638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                for (final ObbState obbState : obbStates) {
2637af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    pw.print("      "); pw.println(obbState.toString());
263838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                }
263938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
2640af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2641af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("");
2642af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("  mObbPathToStateMap:");
2643af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
2644af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            while (maps.hasNext()) {
2645af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                final Entry<String, ObbState> e = maps.next();
2646af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print("    "); pw.print(e.getKey());
2647af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print(" -> "); pw.println(e.getValue().toString());
2648af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
264938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
26504161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root
26514161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root        pw.println("");
26524161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root
2653b049e212ab7fe8967893c202efcb30fecfdb82fbJeff Sharkey        synchronized (mVolumesLock) {
26544161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root            pw.println("  mVolumes:");
26554161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root
26564161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root            final int N = mVolumes.size();
26574161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root            for (int i = 0; i < N; i++) {
26584161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root                final StorageVolume v = mVolumes.get(i);
26594161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root                pw.print("    ");
26604161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root                pw.println(v.toString());
26614161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root            }
26624161f9b30329e558868bb2b16c3e83c0b9cd26fdKenny Root        }
2663470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt
2664470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt        pw.println();
2665470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt        pw.println("  mConnection:");
2666470fd72a06390d7a6b854583afd0ed76ce0a03eeRobert Greenwalt        mConnector.dump(fd, pw, args);
266738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    }
26689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2669fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey    /** {@inheritDoc} */
2670fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey    public void monitor() {
2671fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey        if (mConnector != null) {
2672fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey            mConnector.monitor();
2673fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey        }
2674fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey    }
2675fa23c5ae226c1a1d39f89c5c87d4f340e91d90e0Jeff Sharkey}
2676