MountService.java revision f097fc2fee57183508558acbca1f8742fb55615a
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.server;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport com.android.internal.app.IMediaContainerService;
20c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport com.android.server.am.ActivityManagerService;
21c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
228888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parksimport android.Manifest;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
24a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ComponentName;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
28a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.content.ServiceConnection;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
3002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.content.res.ObbInfo;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri;
3202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Rootimport android.os.Binder;
33a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.Environment;
34c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Handler;
355f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.HandlerThread;
36a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.IBinder;
375f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandlerimport android.os.Looper;
38c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapuimport android.os.Message;
394270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehatimport android.os.RemoteException;
40fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapuimport android.os.ServiceManager;
41207e538350665cea00e1aa70b8094beca4a34e45San Mehatimport android.os.SystemClock;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties;
43a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountService;
44a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountServiceListener;
45a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IMountShutdownObserver;
46a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.IObbActionListener;
47af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Rootimport android.os.storage.OnObbStateChangeListener;
48a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport android.os.storage.StorageResultCode;
49f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parksimport android.text.TextUtils;
50a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehatimport android.util.Slog;
51a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
5238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.FileDescriptor;
5305105f7abe02b2dff91d6260b3628c8b97816babKenny Rootimport java.io.IOException;
5438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.io.PrintWriter;
553b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.math.BigInteger;
56735de3b38abbd6564082a819377673ee593744a6Kenny Rootimport java.security.NoSuchAlgorithmException;
573b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.InvalidKeySpecException;
583b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport java.security.spec.KeySpec;
5922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehatimport java.util.ArrayList;
60a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.HashMap;
616cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehatimport java.util.HashSet;
6238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Iterator;
63a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.LinkedList;
64a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.List;
65a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Rootimport java.util.Map;
6638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Rootimport java.util.Map.Entry;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
683b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKey;
693b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.SecretKeyFactory;
703b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Rootimport javax.crypto.spec.PBEKeySpec;
713b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
73b104340496e3a531e26c8f428c808eca0e039f50San Mehat * MountService implements back-end services for platform storage
74b104340496e3a531e26c8f428c808eca0e039f50San Mehat * management.
75b104340496e3a531e26c8f428c808eca0e039f50San Mehat * @hide - Applications should use android.os.storage.StorageManager
76b104340496e3a531e26c8f428c808eca0e039f50San Mehat * to access the MountService.
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
785af0b916f850486cff4797355bf9e7dc3352fe00Jason parksclass MountService extends IMountService.Stub implements INativeDaemonConnectorCallbacks {
795af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
80b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private static final boolean LOCAL_LOGD = false;
818a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu    private static final boolean DEBUG_UNMOUNT = false;
828a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu    private static final boolean DEBUG_EVENTS = false;
83b7db2726e91f1d9480359d0f83b9cb7769906b34Kenny Root    private static final boolean DEBUG_OBB = false;
8402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "MountService";
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
87305bcbf0c961840c4505770d084a1caacc074dbbKenny Root    private static final String VOLD_TAG = "VoldConnector";
88305bcbf0c961840c4505770d084a1caacc074dbbKenny Root
894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    /*
904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Internal vold volume state constants
914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     */
927fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    class VolumeState {
937fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Init       = -1;
947fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int NoMedia    = 0;
957fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Idle       = 1;
967fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Pending    = 2;
977fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Checking   = 3;
987fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Mounted    = 4;
997fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Unmounting = 5;
1007fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Formatting = 6;
1017fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int Shared     = 7;
1027fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        public static final int SharedMnt  = 8;
1037fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
1047fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
1054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    /*
1064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Internal vold response code constants
1074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     */
10822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    class VoldResponseCode {
1094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 100 series - Requestion action was initiated; expect another reply
1114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         *              before proceeding with a new command.
1124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
11322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeListResult               = 110;
11422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int AsecListResult                 = 111;
115c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        public static final int StorageUsersListResult         = 112;
11622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
1174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 200 series - Requestion action has been successfully completed.
1194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
1204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int ShareStatusResult              = 210;
12122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int AsecPathResult                 = 211;
1224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int ShareEnabledResult             = 212;
12322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
1244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 400 series - Command was accepted, but the requested action
1264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         *              did not take place.
1274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
1284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedNoMedia                = 401;
1294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedMediaBlank             = 402;
1304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedMediaCorrupt           = 403;
1314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public static final int OpFailedVolNotMounted          = 404;
132d970998b0d489774ad1c5b94b47d233912f00214San Mehat        public static final int OpFailedStorageBusy            = 405;
1332d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        public static final int OpFailedStorageNotFound        = 406;
1344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        /*
1364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         * 600 series - Unsolicited broadcasts.
1374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat         */
13822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeStateChange              = 605;
13922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int ShareAvailabilityChange        = 620;
14022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeDiskInserted             = 630;
14122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeDiskRemoved              = 631;
14222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        public static final int VolumeBadRemoval               = 632;
14322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
14422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
1454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private Context                               mContext;
1464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private NativeDaemonConnector                 mConnector;
147f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood    private final HashMap<String, String>         mVolumeStates = new HashMap<String, String>();
148f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood    private String                                mExternalStoragePath;
1494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private PackageManagerService                 mPms;
1504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private boolean                               mUmsEnabling;
1510eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    // Used as a lock for methods that register/unregister listeners.
1520eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    final private ArrayList<MountServiceBinderListener> mListeners =
1530eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            new ArrayList<MountServiceBinderListener>();
1546a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private boolean                               mBooted = false;
1556a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private boolean                               mReady = false;
1566a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private boolean                               mSendUmsConnectedOnBoot = false;
15703559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood    // true if we should fake MEDIA_MOUNTED state for external storage
15803559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood    private boolean                               mEmulateExternalStorage = false;
159fd3530f90562bb7e66edfee39d90fc8beda82f1dSuchi Amalapurapu
1606cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    /**
1616cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat     * Private hash of currently mounted secure containers.
1620eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu     * Used as a lock in methods to manipulate secure containers.
1636cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat     */
1640eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    final private HashSet<String> mAsecMountSet = new HashSet<String>();
1656cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
16602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    /**
1673b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * The size of the crypto algorithm key in bits for OBB files. Currently
1683b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * Twofish is used which takes 128-bit keys.
1693b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     */
1703b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
1713b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
1723b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    /**
1733b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * The number of times to run SHA1 in the PBKDF2 function for OBB files.
1743b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     * 1024 is reasonably secure and not too slow.
1753b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root     */
1763b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    private static final int PBKDF2_HASH_ROUNDS = 1024;
1773b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
1783b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root    /**
179a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * Mounted OBB tracking information. Used to track the current state of all
180a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * OBBs.
181a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     */
182735de3b38abbd6564082a819377673ee593744a6Kenny Root    final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
183a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
184a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
185a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class ObbState implements IBinder.DeathRecipient {
186af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        public ObbState(String filename, int callerUid, IObbActionListener token, int nonce)
187735de3b38abbd6564082a819377673ee593744a6Kenny Root                throws RemoteException {
188a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            this.filename = filename;
189a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            this.callerUid = callerUid;
190af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            this.token = token;
191af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            this.nonce = nonce;
192a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
193a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
194a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        // OBB source filename
195af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        String filename;
196a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
197a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        // Binder.callingUid()
19805105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final public int callerUid;
199a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
200af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        // Token of remote Binder caller
201af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IObbActionListener token;
202af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
203af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        // Identifier to pass back to the token
204af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final int nonce;
205a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
206735de3b38abbd6564082a819377673ee593744a6Kenny Root        public IBinder getBinder() {
207735de3b38abbd6564082a819377673ee593744a6Kenny Root            return token.asBinder();
208735de3b38abbd6564082a819377673ee593744a6Kenny Root        }
209735de3b38abbd6564082a819377673ee593744a6Kenny Root
210a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
211a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void binderDied() {
212a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            ObbAction action = new UnmountObbAction(this, true);
213a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
214735de3b38abbd6564082a819377673ee593744a6Kenny Root        }
215a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2165919ac6b4188285324646772501ef4b97b353cf4Kenny Root        public void link() throws RemoteException {
2175919ac6b4188285324646772501ef4b97b353cf4Kenny Root            getBinder().linkToDeath(this, 0);
2185919ac6b4188285324646772501ef4b97b353cf4Kenny Root        }
2195919ac6b4188285324646772501ef4b97b353cf4Kenny Root
2205919ac6b4188285324646772501ef4b97b353cf4Kenny Root        public void unlink() {
221735de3b38abbd6564082a819377673ee593744a6Kenny Root            getBinder().unlinkToDeath(this, 0);
222a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
22338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
22438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        @Override
22538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        public String toString() {
22638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            StringBuilder sb = new StringBuilder("ObbState{");
22738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append("filename=");
22838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(filename);
22938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(",token=");
23038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(token.toString());
23138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(",callerUid=");
23238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append(callerUid);
23338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            sb.append('}');
23438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return sb.toString();
23538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
236a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
237a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
238a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // OBB Action Handler
239a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private ObbActionHandler mObbActionHandler;
240a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
241a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // OBB action handler messages
242a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_RUN_ACTION = 1;
243a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_BOUND = 2;
244a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_UNBIND = 3;
245a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private static final int OBB_MCS_RECONNECT = 4;
246af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private static final int OBB_FLUSH_MOUNT_STATE = 5;
247a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
248a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    /*
249a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root     * Default Container Service information
25002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root     */
251a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
252a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
253a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
254a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
255a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
256a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class DefaultContainerConnection implements ServiceConnection {
257a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void onServiceConnected(ComponentName name, IBinder service) {
258a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
259a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "onServiceConnected");
260a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
261a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
262a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
263a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
264a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void onServiceDisconnected(ComponentName name) {
265a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
266a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "onServiceDisconnected");
267a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
268a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    };
269a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
270a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    // Used in the ObbActionHandler
271a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private IMediaContainerService mContainerService = null;
27202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
27302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    // Handler messages
274c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_PM_UPDATE = 1;
275c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_PM_DONE = 2;
276c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int H_UNMOUNT_MS = 3;
277c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int RETRY_UNMOUNT_DELAY = 30; // in ms
278c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    private static final int MAX_UNMOUNT_RETRIES = 4;
279c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
280c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    class UnmountCallBack {
28105105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final String path;
28205105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final boolean force;
283c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        int retries;
284c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
285c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        UnmountCallBack(String path, boolean force) {
286c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            retries = 0;
287c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            this.path = path;
288c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            this.force = force;
289c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        }
2900eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
2910eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        void handleFinished() {
292a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path);
2930eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            doUnmountVolume(path, true);
2940eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
2950eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
2960eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
2970eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    class UmsEnableCallBack extends UnmountCallBack {
29805105f7abe02b2dff91d6260b3628c8b97816babKenny Root        final String method;
2990eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3000eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        UmsEnableCallBack(String path, String method, boolean force) {
3010eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            super(path, force);
3020eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            this.method = method;
3030eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
3040eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
3050eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        @Override
3060eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        void handleFinished() {
3070eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            super.handleFinished();
3080eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            doShareUnshareVolume(path, method, true);
3090eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
310c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    }
311c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
3126ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    class ShutdownCallBack extends UnmountCallBack {
3136ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        IMountShutdownObserver observer;
3146ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        ShutdownCallBack(String path, IMountShutdownObserver observer) {
3156ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            super(path, true);
3166ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            this.observer = observer;
3176ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        }
3186ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3196ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        @Override
3206ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        void handleFinished() {
3216ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            int ret = doUnmountVolume(path, true);
3226ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            if (observer != null) {
3236ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                try {
3246ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    observer.onShutDownComplete(ret);
3256ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                } catch (RemoteException e) {
326a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.w(TAG, "RemoteException when shutting down");
3276ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                }
3286ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu            }
3296ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu        }
3306ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    }
3316ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3325f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler    class MountServiceHandler extends Handler {
333c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>();
334e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        boolean mUpdatingStatus = false;
3356ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu
3365f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        MountServiceHandler(Looper l) {
3375f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler            super(l);
3385f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        }
3395f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler
3405af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
341c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        public void handleMessage(Message msg) {
342c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            switch (msg.what) {
343c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                case H_UNMOUNT_PM_UPDATE: {
344a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_UPDATE");
345c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    UnmountCallBack ucb = (UnmountCallBack) msg.obj;
346c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    mForceUnmounts.add(ucb);
347a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, " registered = " + mUpdatingStatus);
3486ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    // Register only if needed.
349e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                    if (!mUpdatingStatus) {
350a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        if (DEBUG_UNMOUNT) Slog.i(TAG, "Updating external media status on PackageManager");
351e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                        mUpdatingStatus = true;
352e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                        mPms.updateExternalMediaStatus(false, true);
353c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    }
354c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
355c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
356c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                case H_UNMOUNT_PM_DONE: {
357a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_PM_DONE");
358a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "Updated status. Processing requests");
359e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                    mUpdatingStatus = false;
3606ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int size = mForceUnmounts.size();
3616ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int sizeArr[] = new int[size];
3626ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    int sizeArrN = 0;
3637af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    // Kill processes holding references first
3647af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    ActivityManagerService ams = (ActivityManagerService)
3657af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                    ServiceManager.getService("activity");
3666ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    for (int i = 0; i < size; i++) {
3676ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        UnmountCallBack ucb = mForceUnmounts.get(i);
3686ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        String path = ucb.path;
3696ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        boolean done = false;
3706ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        if (!ucb.force) {
371c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                            done = true;
372c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        } else {
3736ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            int pids[] = getStorageUsers(path);
3746ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            if (pids == null || pids.length == 0) {
3756ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                                done = true;
3766ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            } else {
3776ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                                // Eliminate system process here?
378648251710162cdaf7371012a1cbb79b9bc5bc0e4Dianne Hackborn                                ams.killPids(pids, "unmount media", true);
3797af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                // Confirm if file references have been freed.
3807af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                pids = getStorageUsers(path);
3817af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                if (pids == null || pids.length == 0) {
3827af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    done = true;
383c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                                }
384c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                            }
385c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        }
3867af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                        if (!done && (ucb.retries < MAX_UNMOUNT_RETRIES)) {
3877af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            // Retry again
3887af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            Slog.i(TAG, "Retrying to kill storage users again");
3897af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            mHandler.sendMessageDelayed(
3907af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    mHandler.obtainMessage(H_UNMOUNT_PM_DONE,
3917af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                            ucb.retries++),
3927af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    RETRY_UNMOUNT_DELAY);
393c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        } else {
3946ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            if (ucb.retries >= MAX_UNMOUNT_RETRIES) {
3957af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                Slog.i(TAG, "Failed to unmount media inspite of " +
3967af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                        MAX_UNMOUNT_RETRIES + " retries. Forcibly killing processes now");
3976ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                            }
3987af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            sizeArr[sizeArrN++] = i;
3997af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                            mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS,
4007af074a6124d2293bc979e24f3258166efb8a310Suchi Amalapurapu                                    ucb));
401c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                        }
402c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    }
4036ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    // Remove already processed elements from list.
4046ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    for (int i = (sizeArrN-1); i >= 0; i--) {
4056ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                        mForceUnmounts.remove(sizeArr[i]);
4066ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu                    }
407c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
408c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
409c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                case H_UNMOUNT_MS : {
410a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    if (DEBUG_UNMOUNT) Slog.i(TAG, "H_UNMOUNT_MS");
411c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    UnmountCallBack ucb = (UnmountCallBack) msg.obj;
4120eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                    ucb.handleFinished();
413c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                    break;
414c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu                }
415c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu            }
416c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        }
417c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    };
4185f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler    final private HandlerThread mHandlerThread;
4195f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler    final private Handler mHandler;
420c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu
421207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void waitForReady() {
422207e538350665cea00e1aa70b8094beca4a34e45San Mehat        while (mReady == false) {
423207e538350665cea00e1aa70b8094beca4a34e45San Mehat            for (int retries = 5; retries > 0; retries--) {
424207e538350665cea00e1aa70b8094beca4a34e45San Mehat                if (mReady) {
425207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    return;
426207e538350665cea00e1aa70b8094beca4a34e45San Mehat                }
427207e538350665cea00e1aa70b8094beca4a34e45San Mehat                SystemClock.sleep(1000);
428207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
429a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.w(TAG, "Waiting too long for mReady!");
430207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
4311f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat    }
43202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
433207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
4345af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
43691c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat            String action = intent.getAction();
43791c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
43891c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat            if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
439207e538350665cea00e1aa70b8094beca4a34e45San Mehat                mBooted = true;
44022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
441c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                /*
442c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                 * In the simulator, we need to broadcast a volume mounted event
443c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                 * to make the media scanner run.
444c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                 */
445c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
446c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                    notifyVolumeStateChange(null, "/sdcard", VolumeState.NoMedia, VolumeState.Mounted);
447c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                    return;
448c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen                }
449fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                new Thread() {
4505af0b916f850486cff4797355bf9e7dc3352fe00Jason parks                    @Override
451fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                    public void run() {
452fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                        try {
453f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                            synchronized (mVolumeStates) {
454f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                                for (String path : mVolumeStates.keySet()) {
455f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                                    String state = mVolumeStates.get(path);
456f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood
457f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                                    if (state.equals(Environment.MEDIA_UNMOUNTED)) {
458f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                                        int rc = doMountVolume(path);
459f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                                        if (rc != StorageResultCode.OperationSucceeded) {
460f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                                            Slog.e(TAG, String.format("Boot-time mount failed (%d)",
461f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                                                    rc));
462f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                                        }
463f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                                    } else if (state.equals(Environment.MEDIA_SHARED)) {
464f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                                        /*
465f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                                         * Bootstrap UMS enabled state since vold indicates
466f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                                         * the volume is shared (runtime restart while ums enabled)
467f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                                         */
468f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                                        notifyVolumeStateChange(null, path, VolumeState.NoMedia,
469f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                                                VolumeState.Shared);
470f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                                    }
471fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                                }
472fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                            }
4736a254403235196692b1769d2fe281b0852c0cc25San Mehat
4746a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                            /*
4756a254403235196692b1769d2fe281b0852c0cc25San Mehat                             * If UMS was connected on boot, send the connected event
4766a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                             * now that we're up.
4776a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                             */
4786a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                            if (mSendUmsConnectedOnBoot) {
4796a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                                sendUmsIntent(true);
4806a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                                mSendUmsConnectedOnBoot = false;
4816a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                            }
482fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                        } catch (Exception ex) {
483a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.e(TAG, "Boot-time mount exception", ex);
484fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                        }
485207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    }
486fafb041b47c1c5f6a4c253768295ed3aeb7ad412San Mehat                }.start();
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    private final class MountServiceBinderListener implements IBinder.DeathRecipient {
4924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        final IMountServiceListener mListener;
49391c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
4944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        MountServiceBinderListener(IMountServiceListener listener) {
4954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mListener = listener;
49602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
49791c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat        }
49891c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
4994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        public void binderDied() {
500a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!");
501a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            synchronized (mListeners) {
5024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListeners.remove(this);
5034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListener.asBinder().unlinkToDeath(this, 0);
50491c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat            }
50591c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat        }
50691c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat    }
50791c7761139c0931da0fcbc89bce38cee4b9cc535San Mehat
5080eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private void doShareUnshareVolume(String path, String method, boolean enable) {
5094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        // TODO: Add support for multiple share methods
5104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (!method.equals("ums")) {
5114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            throw new IllegalArgumentException(String.format("Method %s not supported", method));
5127fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
5154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(String.format(
5164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    "volume %sshare %s %s", (enable ? "" : "un"), path, method));
5174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
518a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Failed to share/unshare", e);
51922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
522207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void updatePublicVolumeState(String path, String state) {
523f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood        String oldState;
524f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood        synchronized(mVolumeStates) {
525f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            oldState = mVolumeStates.put(path, state);
5267fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
527f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood        if (state.equals(oldState)) {
528f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            Slog.w(TAG, String.format("Duplicate state transition (%s -> %s) for %s",
529f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    state, state, path));
530b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return;
531b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
532af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
533f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood        Slog.d(TAG, "volume state changed for " + path + " (" + oldState + " -> " + state + ")");
534f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood
535f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood        if (path.equals(mExternalStoragePath)) {
536f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            // Update state on PackageManager, but only of real events
537f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            if (!mEmulateExternalStorage) {
538f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                if (Environment.MEDIA_UNMOUNTED.equals(state)) {
539f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    mPms.updateExternalMediaStatus(false, false);
540f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood
541f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    /*
542f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * Some OBBs might have been unmounted when this volume was
543f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * unmounted, so send a message to the handler to let it know to
544f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * remove those from the list of mounted OBBS.
545f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     */
546f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
547f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                            OBB_FLUSH_MOUNT_STATE, path));
548f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                } else if (Environment.MEDIA_MOUNTED.equals(state)) {
549f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    mPms.updateExternalMediaStatus(true, false);
550f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                }
55103559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood            }
5528a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
5534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
5544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for (int i = mListeners.size() -1; i >= 0; i--) {
5554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                MountServiceBinderListener bl = mListeners.get(i);
5564270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                try {
557b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    bl.mListener.onStorageStateChanged(path, oldState, state);
5584270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (RemoteException rex) {
559a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener dead");
5604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(i);
5614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (Exception ex) {
562a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener failed", ex);
5634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
56822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    /**
56922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     *
57022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     * Callback from NativeDaemonConnector
57122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     */
57222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    public void onDaemonConnected() {
5735b77dab23469273d41f9c530d947ac055765e6eaSan Mehat        /*
5745b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         * Since we'll be calling back into the NativeDaemonConnector,
5755b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         * we need to do our work in a new thread.
5765b77dab23469273d41f9c530d947ac055765e6eaSan Mehat         */
5777fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        new Thread() {
5785af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            @Override
5797fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            public void run() {
5805b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                /**
5815b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                 * Determine media state and UMS detection status
5825b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                 */
5837fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                try {
5845b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                    String[] vols = mConnector.doListCommand(
5854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        "volume list", VoldResponseCode.VolumeListResult);
5865b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                    for (String volstr : vols) {
5875b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        String[] tok = volstr.split(" ");
5885b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        // FMT: <label> <mountpoint> <state>
589f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        String path = tok[1];
590f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        String state = Environment.MEDIA_REMOVED;
591f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood
5925b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        int st = Integer.parseInt(tok[2]);
5935b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        if (st == VolumeState.NoMedia) {
5945b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_REMOVED;
5955b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Idle) {
596207e538350665cea00e1aa70b8094beca4a34e45San Mehat                            state = Environment.MEDIA_UNMOUNTED;
5975b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Mounted) {
5985b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_MOUNTED;
599a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.i(TAG, "Media already mounted on daemon connection");
6005b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else if (st == VolumeState.Shared) {
6015b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            state = Environment.MEDIA_SHARED;
602a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.i(TAG, "Media shared on daemon connection");
6035b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                        } else {
6045b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                            throw new Exception(String.format("Unexpected state %d", st));
6057fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                        }
606f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood
607f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        if (state != null) {
608f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                            if (DEBUG_EVENTS) Slog.i(TAG, "Updating valid state " + state);
609f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                            updatePublicVolumeState(path, state);
610f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        }
611c2a39471642e31d7350910612e40d078b825173aSan Mehat                    }
6125b77dab23469273d41f9c530d947ac055765e6eaSan Mehat                } catch (Exception e) {
613a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Error processing initial volume state", e);
614f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    updatePublicVolumeState(mExternalStoragePath, Environment.MEDIA_REMOVED);
6157fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                }
6167fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
6177fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                try {
618207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    boolean avail = doGetShareMethodAvailable("ums");
6197fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                    notifyShareAvailabilityChange("ums", avail);
6207fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                } catch (Exception ex) {
621a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.w(TAG, "Failed to get share availability");
6227fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat                }
623207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
6249ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                 * Now that we've done our initialization, release
625207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * the hounds!
626207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
627207e538350665cea00e1aa70b8094beca4a34e45San Mehat                mReady = true;
6287fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            }
6297fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }.start();
6307fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
6317fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
63222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    /**
63322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     * Callback from NativeDaemonConnector
63422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat     */
63522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    public boolean onEvent(int code, String raw, String[] cooked) {
6364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        Intent in = null;
6374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
6388a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        if (DEBUG_EVENTS) {
6398a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            StringBuilder builder = new StringBuilder();
6408a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            builder.append("onEvent::");
6418a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            builder.append(" raw= " + raw);
6428a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            if (cooked != null) {
6438a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                builder.append(" cooked = " );
6448a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                for (String str : cooked) {
6458a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                    builder.append(" " + str);
6468a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                }
6478a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            }
648a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.i(TAG, builder.toString());
6498a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
65022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        if (code == VoldResponseCode.VolumeStateChange) {
6514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            /*
6524270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * One of the volumes we're managing has changed state.
6534270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * Format: "NNN Volume <label> <path> state changed
6544270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             * from <old_#> (<old_str>) to <new_#> (<new_str>)"
6554270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat             */
65622dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            notifyVolumeStateChange(
65722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat                    cooked[2], cooked[3], Integer.parseInt(cooked[7]),
65822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat                            Integer.parseInt(cooked[10]));
65922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        } else if (code == VoldResponseCode.ShareAvailabilityChange) {
66022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Share method <method> now <available|unavailable>
66122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            boolean avail = false;
66222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            if (cooked[5].equals("available")) {
66322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat                avail = true;
66422dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            }
66522dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            notifyShareAvailabilityChange(cooked[3], avail);
6664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } else if ((code == VoldResponseCode.VolumeDiskInserted) ||
6674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                   (code == VoldResponseCode.VolumeDiskRemoved) ||
6684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                   (code == VoldResponseCode.VolumeBadRemoval)) {
66922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> disk inserted (<major>:<minor>)
67022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> disk removed (<major>:<minor>)
67122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            // FMT: NNN Volume <label> <mountpoint> bad removal (<major>:<minor>)
6724270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            final String label = cooked[2];
6734270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            final String path = cooked[3];
6744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            int major = -1;
6754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            int minor = -1;
6764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
6774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            try {
6784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                String devComp = cooked[6].substring(1, cooked[6].length() -1);
6794270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                String[] devTok = devComp.split(":");
6804270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                major = Integer.parseInt(devTok[0]);
6814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                minor = Integer.parseInt(devTok[1]);
6824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } catch (Exception ex) {
683a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to parse major/minor", ex);
6844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
6854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
6864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            if (code == VoldResponseCode.VolumeDiskInserted) {
6874270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                new Thread() {
6885af0b916f850486cff4797355bf9e7dc3352fe00Jason parks                    @Override
6894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    public void run() {
6904270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        try {
6914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                            int rc;
692b104340496e3a531e26c8f428c808eca0e039f50San Mehat                            if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
693a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                                Slog.w(TAG, String.format("Insertion mount failed (%d)", rc));
6944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                            }
6954270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        } catch (Exception ex) {
696a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.w(TAG, "Failed to mount media on insertion", ex);
6974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                        }
6984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    }
6994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }.start();
7004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else if (code == VoldResponseCode.VolumeDiskRemoved) {
7014270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /*
7024270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                 * This event gets trumped if we're already in BAD_REMOVAL state
7034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                 */
7044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                if (getVolumeState(path).equals(Environment.MEDIA_BAD_REMOVAL)) {
7054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    return true;
7064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
7074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /* Send the media unmounted event first */
708a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
7094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
7104270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
7114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mContext.sendBroadcast(in);
7124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
713a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending media removed");
7144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_REMOVED);
7154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                in = new Intent(Intent.ACTION_MEDIA_REMOVED, Uri.parse("file://" + path));
7164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else if (code == VoldResponseCode.VolumeBadRemoval) {
717a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending unmounted event first");
7184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                /* Send the media unmounted event first */
7194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
7204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
7214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mContext.sendBroadcast(in);
7224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
723a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "Sending media bad removal");
7244270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_BAD_REMOVAL);
7254270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                in = new Intent(Intent.ACTION_MEDIA_BAD_REMOVAL, Uri.parse("file://" + path));
7264270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } else {
727a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Unknown code {%d}", code));
7284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
72922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        } else {
73022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            return false;
73122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
7324270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
7334270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (in != null) {
7344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mContext.sendBroadcast(in);
7355f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        }
7365f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        return true;
73722dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
73822dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat
739207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void notifyVolumeStateChange(String label, String path, int oldState, int newState) {
7404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        String vs = getVolumeState(path);
741a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        if (DEBUG_EVENTS) Slog.i(TAG, "notifyVolumeStateChanged::" + vs);
7424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
7434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        Intent in = null;
7447fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
745bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood        if (oldState == VolumeState.Shared && newState != oldState) {
746a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_UNSHARED intent");
747bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood            mContext.sendBroadcast(new Intent(Intent.ACTION_MEDIA_UNSHARED,
748bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood                                                Uri.parse("file://" + path)));
749bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood        }
750bf2dd44a6f86d13efd55d1e690822fba11187bf8Mike Lockwood
7517fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        if (newState == VolumeState.Init) {
7527fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.NoMedia) {
7537fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            // NoMedia is handled via Disk Remove events
7547fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Idle) {
7555fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat            /*
7565fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             * Don't notify if we're in BAD_REMOVAL, NOFS, UNMOUNTABLE, or
7575fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             * if we're in the process of enabling UMS
7585fbf4094f5857ab15801c65a260a5c4b6866d655San Mehat             */
7594270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            if (!vs.equals(
7604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    Environment.MEDIA_BAD_REMOVAL) && !vs.equals(
7614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                            Environment.MEDIA_NOFS) && !vs.equals(
7620eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                                    Environment.MEDIA_UNMOUNTABLE) && !getUmsEnabling()) {
763a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state for media bad removal nofs and unmountable");
7644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
7654270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
7667fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat            }
7677fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Pending) {
7687fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Checking) {
769a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state checking");
7704270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            updatePublicVolumeState(path, Environment.MEDIA_CHECKING);
7714270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            in = new Intent(Intent.ACTION_MEDIA_CHECKING, Uri.parse("file://" + path));
7727fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Mounted) {
773a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state mounted");
7744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            updatePublicVolumeState(path, Environment.MEDIA_MOUNTED);
7754270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            in = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + path));
7764270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            in.putExtra("read-only", false);
7777fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Unmounting) {
7784270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            in = new Intent(Intent.ACTION_MEDIA_EJECT, Uri.parse("file://" + path));
7797fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Formatting) {
7807fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.Shared) {
781a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "Updating volume state media mounted");
7824270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            /* Send the media unmounted event first */
7834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTED);
7844270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            in = new Intent(Intent.ACTION_MEDIA_UNMOUNTED, Uri.parse("file://" + path));
7854270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mContext.sendBroadcast(in);
7864270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
787a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (DEBUG_EVENTS) Slog.i(TAG, "Updating media shared");
7884270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            updatePublicVolumeState(path, Environment.MEDIA_SHARED);
7894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            in = new Intent(Intent.ACTION_MEDIA_SHARED, Uri.parse("file://" + path));
790a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            if (LOCAL_LOGD) Slog.d(TAG, "Sending ACTION_MEDIA_SHARED intent");
7917fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else if (newState == VolumeState.SharedMnt) {
792a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Live shared mounts not supported yet!");
7934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            return;
7947fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        } else {
795a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Unhandled VolumeState {" + newState + "}");
7967fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
7977fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
7984270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (in != null) {
7994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mContext.sendBroadcast(in);
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
803207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private boolean doGetShareMethodAvailable(String method) {
80485fb20665feadda526ad422c093b859e8c4d40bcKenny Root        ArrayList<String> rsp;
805a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
80685fb20665feadda526ad422c093b859e8c4d40bcKenny Root            rsp = mConnector.doCommand("share status " + method);
807a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException ex) {
808a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            Slog.e(TAG, "Failed to determine whether share method " + method + " is available.");
809a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            return false;
810a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
811207e538350665cea00e1aa70b8094beca4a34e45San Mehat
812207e538350665cea00e1aa70b8094beca4a34e45San Mehat        for (String line : rsp) {
813a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            String[] tok = line.split(" ");
814a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            if (tok.length < 3) {
815a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                Slog.e(TAG, "Malformed response to share status " + method);
816a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                return false;
817a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            }
818a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root
819207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code;
820207e538350665cea00e1aa70b8094beca4a34e45San Mehat            try {
821207e538350665cea00e1aa70b8094beca4a34e45San Mehat                code = Integer.parseInt(tok[0]);
822207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } catch (NumberFormatException nfe) {
823a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
824207e538350665cea00e1aa70b8094beca4a34e45San Mehat                return false;
825207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
826207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.ShareStatusResult) {
827207e538350665cea00e1aa70b8094beca4a34e45San Mehat                if (tok[2].equals("available"))
828207e538350665cea00e1aa70b8094beca4a34e45San Mehat                    return true;
829207e538350665cea00e1aa70b8094beca4a34e45San Mehat                return false;
830207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
831a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Unexpected response code %d", code));
832207e538350665cea00e1aa70b8094beca4a34e45San Mehat                return false;
833207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
834207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
835a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        Slog.e(TAG, "Got an empty response");
836207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return false;
837207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
838207e538350665cea00e1aa70b8094beca4a34e45San Mehat
839207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private int doMountVolume(String path) {
840b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
841207e538350665cea00e1aa70b8094beca4a34e45San Mehat
842a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        if (DEBUG_EVENTS) Slog.i(TAG, "doMountVolume: Mouting " + path);
843207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
844207e538350665cea00e1aa70b8094beca4a34e45San Mehat            mConnector.doCommand(String.format("volume mount %s", path));
845207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
846207e538350665cea00e1aa70b8094beca4a34e45San Mehat            /*
847207e538350665cea00e1aa70b8094beca4a34e45San Mehat             * Mount failed for some reason
848207e538350665cea00e1aa70b8094beca4a34e45San Mehat             */
849207e538350665cea00e1aa70b8094beca4a34e45San Mehat            Intent in = null;
850207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
851207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedNoMedia) {
852207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
853207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Attempt to mount but no media inserted
854207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
855b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedNoMedia;
856207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaBlank) {
857a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, " updating volume state :: media nofs");
858207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
859207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Media is blank or does not contain a supported filesystem
860207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
861207e538350665cea00e1aa70b8094beca4a34e45San Mehat                updatePublicVolumeState(path, Environment.MEDIA_NOFS);
862207e538350665cea00e1aa70b8094beca4a34e45San Mehat                in = new Intent(Intent.ACTION_MEDIA_NOFS, Uri.parse("file://" + path));
863b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedMediaBlank;
864207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
865a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                if (DEBUG_EVENTS) Slog.i(TAG, "updating volume state media corrupt");
866207e538350665cea00e1aa70b8094beca4a34e45San Mehat                /*
867207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 * Volume consistency check failed
868207e538350665cea00e1aa70b8094beca4a34e45San Mehat                 */
869207e538350665cea00e1aa70b8094beca4a34e45San Mehat                updatePublicVolumeState(path, Environment.MEDIA_UNMOUNTABLE);
870207e538350665cea00e1aa70b8094beca4a34e45San Mehat                in = new Intent(Intent.ACTION_MEDIA_UNMOUNTABLE, Uri.parse("file://" + path));
871b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedMediaCorrupt;
872207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
873b104340496e3a531e26c8f428c808eca0e039f50San Mehat                rc = StorageResultCode.OperationFailedInternalError;
874207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
875207e538350665cea00e1aa70b8094beca4a34e45San Mehat
876207e538350665cea00e1aa70b8094beca4a34e45San Mehat            /*
877207e538350665cea00e1aa70b8094beca4a34e45San Mehat             * Send broadcast intent (if required for the failure)
878207e538350665cea00e1aa70b8094beca4a34e45San Mehat             */
879207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (in != null) {
880207e538350665cea00e1aa70b8094beca4a34e45San Mehat                mContext.sendBroadcast(in);
881207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
882207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
883207e538350665cea00e1aa70b8094beca4a34e45San Mehat
884207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return rc;
885207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
886207e538350665cea00e1aa70b8094beca4a34e45San Mehat
887c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    /*
888c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * If force is not set, we do not unmount if there are
889c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * processes holding references to the volume about to be unmounted.
890c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * If force is set, all the processes holding references need to be
891c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * killed via the ActivityManager before actually unmounting the volume.
892c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * This might even take a while and might be retried after timed delays
893c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * to make sure we dont end up in an instable state and kill some core
894c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     * processes.
895c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu     */
896d970998b0d489774ad1c5b94b47d233912f00214San Mehat    private int doUnmountVolume(String path, boolean force) {
89759443a673a736978361dc341f41ce4e9dae053a0San Mehat        if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
898207e538350665cea00e1aa70b8094beca4a34e45San Mehat            return VoldResponseCode.OpFailedVolNotMounted;
899207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
900aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
901aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
902aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
903aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
904aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
905aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
906aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
907aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
908aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
909c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        // Redundant probably. But no harm in updating state again.
910e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        mPms.updateExternalMediaStatus(false, false);
911207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
912d970998b0d489774ad1c5b94b47d233912f00214San Mehat            mConnector.doCommand(String.format(
913d970998b0d489774ad1c5b94b47d233912f00214San Mehat                    "volume unmount %s%s", path, (force ? " force" : "")));
914e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            // We unmounted the volume. None of the asec containers are available now.
915e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            synchronized (mAsecMountSet) {
916e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu                mAsecMountSet.clear();
917e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu            }
918b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return StorageResultCode.OperationSucceeded;
919207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
920207e538350665cea00e1aa70b8094beca4a34e45San Mehat            // Don't worry about mismatch in PackageManager since the
921207e538350665cea00e1aa70b8094beca4a34e45San Mehat            // call back will handle the status changes any way.
922207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
923207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedVolNotMounted) {
924a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageNotMounted;
925d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else if (code == VoldResponseCode.OpFailedStorageBusy) {
926d970998b0d489774ad1c5b94b47d233912f00214San Mehat                return StorageResultCode.OperationFailedStorageBusy;
927207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
928b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedInternalError;
929207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
930207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
931207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
932207e538350665cea00e1aa70b8094beca4a34e45San Mehat
933207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private int doFormatVolume(String path) {
934207e538350665cea00e1aa70b8094beca4a34e45San Mehat        try {
935207e538350665cea00e1aa70b8094beca4a34e45San Mehat            String cmd = String.format("volume format %s", path);
936207e538350665cea00e1aa70b8094beca4a34e45San Mehat            mConnector.doCommand(cmd);
937b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return StorageResultCode.OperationSucceeded;
938207e538350665cea00e1aa70b8094beca4a34e45San Mehat        } catch (NativeDaemonConnectorException e) {
939207e538350665cea00e1aa70b8094beca4a34e45San Mehat            int code = e.getCode();
940207e538350665cea00e1aa70b8094beca4a34e45San Mehat            if (code == VoldResponseCode.OpFailedNoMedia) {
941b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedNoMedia;
942207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else if (code == VoldResponseCode.OpFailedMediaCorrupt) {
943b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedMediaCorrupt;
944207e538350665cea00e1aa70b8094beca4a34e45San Mehat            } else {
945b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return StorageResultCode.OperationFailedInternalError;
946207e538350665cea00e1aa70b8094beca4a34e45San Mehat            }
947207e538350665cea00e1aa70b8094beca4a34e45San Mehat        }
948207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
949207e538350665cea00e1aa70b8094beca4a34e45San Mehat
950b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private boolean doGetVolumeShared(String path, String method) {
951b104340496e3a531e26c8f428c808eca0e039f50San Mehat        String cmd = String.format("volume shared %s %s", path, method);
952a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        ArrayList<String> rsp;
953a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root
954a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        try {
955a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            rsp = mConnector.doCommand(cmd);
956a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        } catch (NativeDaemonConnectorException ex) {
957a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            Slog.e(TAG, "Failed to read response to volume shared " + path + " " + method);
958a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            return false;
959a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root        }
960b104340496e3a531e26c8f428c808eca0e039f50San Mehat
961b104340496e3a531e26c8f428c808eca0e039f50San Mehat        for (String line : rsp) {
962a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            String[] tok = line.split(" ");
963a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            if (tok.length < 3) {
964a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                Slog.e(TAG, "Malformed response to volume shared " + path + " " + method + " command");
965a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                return false;
966a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root            }
967a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root
968b104340496e3a531e26c8f428c808eca0e039f50San Mehat            int code;
969b104340496e3a531e26c8f428c808eca0e039f50San Mehat            try {
970b104340496e3a531e26c8f428c808eca0e039f50San Mehat                code = Integer.parseInt(tok[0]);
971b104340496e3a531e26c8f428c808eca0e039f50San Mehat            } catch (NumberFormatException nfe) {
972a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Error parsing code %s", tok[0]));
973b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return false;
974b104340496e3a531e26c8f428c808eca0e039f50San Mehat            }
975b104340496e3a531e26c8f428c808eca0e039f50San Mehat            if (code == VoldResponseCode.ShareEnabledResult) {
976a80ce06d4c54e43243073f8ceff024f9dda7140eKenny Root                return "enabled".equals(tok[2]);
977b104340496e3a531e26c8f428c808eca0e039f50San Mehat            } else {
978a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, String.format("Unexpected response code %d", code));
979b104340496e3a531e26c8f428c808eca0e039f50San Mehat                return false;
980b104340496e3a531e26c8f428c808eca0e039f50San Mehat            }
981b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
982a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        Slog.e(TAG, "Got an empty response");
983b104340496e3a531e26c8f428c808eca0e039f50San Mehat        return false;
984b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
985b104340496e3a531e26c8f428c808eca0e039f50San Mehat
986207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void notifyShareAvailabilityChange(String method, final boolean avail) {
9877fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        if (!method.equals("ums")) {
988a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat           Slog.w(TAG, "Ignoring unsupported share method {" + method + "}");
9897fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat           return;
9907fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
9911f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat
9924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
9934270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for (int i = mListeners.size() -1; i >= 0; i--) {
9944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                MountServiceBinderListener bl = mListeners.get(i);
9951f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                try {
996b104340496e3a531e26c8f428c808eca0e039f50San Mehat                    bl.mListener.onUsbMassStorageConnectionChanged(avail);
9974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                } catch (RemoteException rex) {
998a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener dead");
9994270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(i);
10001f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                } catch (Exception ex) {
1001a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, "Listener failed", ex);
10021f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat                }
10031f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat            }
10044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        }
10057fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
1006207e538350665cea00e1aa70b8094beca4a34e45San Mehat        if (mBooted == true) {
10076a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat            sendUmsIntent(avail);
10086a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat        } else {
10096a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat            mSendUmsConnectedOnBoot = avail;
10101f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat        }
10112fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat
10122fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat        final String path = Environment.getExternalStorageDirectory().getPath();
10132fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat        if (avail == false && getVolumeState(path).equals(Environment.MEDIA_SHARED)) {
10142fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            /*
10152fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat             * USB mass storage disconnected while enabled
10162fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat             */
10172fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            new Thread() {
10185af0b916f850486cff4797355bf9e7dc3352fe00Jason parks                @Override
10192fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                public void run() {
10202fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    try {
10212fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        int rc;
1022a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        Slog.w(TAG, "Disabling UMS after cable disconnect");
10232fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        doShareUnshareVolume(path, "ums", false);
10242fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        if ((rc = doMountVolume(path)) != StorageResultCode.OperationSucceeded) {
1025a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                            Slog.e(TAG, String.format(
10262fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                                    "Failed to remount {%s} on UMS enabled-disconnect (%d)",
10272fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                                            path, rc));
10282fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                        }
10292fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    } catch (Exception ex) {
1030a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                        Slog.w(TAG, "Failed to mount media on UMS enabled-disconnect", ex);
10312fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                    }
10322fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat                }
10332fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat            }.start();
10342fe718a87b9ebc9679ff2abf38b6c30274267beaSan Mehat        }
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10376a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    private void sendUmsIntent(boolean c) {
10386a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat        mContext.sendBroadcast(
10396a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat                new Intent((c ? Intent.ACTION_UMS_CONNECTED : Intent.ACTION_UMS_DISCONNECTED)));
10406a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat    }
10416a965af2d76f6cf3ec980c8ecfd257f49b3c97e3San Mehat
1042207e538350665cea00e1aa70b8094beca4a34e45San Mehat    private void validatePermission(String perm) {
10434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
10444270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            throw new SecurityException(String.format("Requires %s permission", perm));
10454270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        }
10467fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat    }
10477fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1049207e538350665cea00e1aa70b8094beca4a34e45San Mehat     * Constructs a new MountService instance
1050207e538350665cea00e1aa70b8094beca4a34e45San Mehat     *
1051207e538350665cea00e1aa70b8094beca4a34e45San Mehat     * @param context  Binder context for this service
1052207e538350665cea00e1aa70b8094beca4a34e45San Mehat     */
1053207e538350665cea00e1aa70b8094beca4a34e45San Mehat    public MountService(Context context) {
1054207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mContext = context;
1055207e538350665cea00e1aa70b8094beca4a34e45San Mehat
1056f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood        mExternalStoragePath = Environment.getExternalStorageDirectory().getPath();
105703559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood        mEmulateExternalStorage = context.getResources().getBoolean(
105803559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood                com.android.internal.R.bool.config_emulateExternalStorage);
105903559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood        if (mEmulateExternalStorage) {
106003559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood            Slog.d(TAG, "using emulated external storage");
1061f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            mVolumeStates.put(mExternalStoragePath, Environment.MEDIA_MOUNTED);
106203559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood        }
106303559753ce0c6105b9357d6050aa4cddb9112ac2Mike Lockwood
1064207e538350665cea00e1aa70b8094beca4a34e45San Mehat        // XXX: This will go away soon in favor of IMountServiceObserver
1065207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mPms = (PackageManagerService) ServiceManager.getService("package");
1066207e538350665cea00e1aa70b8094beca4a34e45San Mehat
1067207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mContext.registerReceiver(mBroadcastReceiver,
1068207e538350665cea00e1aa70b8094beca4a34e45San Mehat                new IntentFilter(Intent.ACTION_BOOT_COMPLETED), null, null);
1069207e538350665cea00e1aa70b8094beca4a34e45San Mehat
10705f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandlerThread = new HandlerThread("MountService");
10715f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandlerThread.start();
10725f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler        mHandler = new MountServiceHandler(mHandlerThread.getLooper());
10735f27ef4968ac8c331157524c60a4511fcc3731b1Daniel Sandler
1074a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        // Add OBB Action Handler to MountService thread.
1075a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        mObbActionHandler = new ObbActionHandler(mHandlerThread.getLooper());
1076a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1077c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen        /*
1078c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen         * Vold does not run in the simulator, so pretend the connector thread
1079c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen         * ran and did its thing.
1080c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen         */
1081c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen        if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
1082c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen            mReady = true;
1083c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen            mUmsEnabling = true;
1084c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen            return;
1085c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen        }
1086c34ebce475a6994f1aa59b8c535ff966c8f59431Marco Nelissen
1087305bcbf0c961840c4505770d084a1caacc074dbbKenny Root        /*
1088305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * Create the connection to vold with a maximum queue of twice the
1089305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * amount of containers we'd ever expect to have. This keeps an
1090305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         * "asec list" from blocking a thread repeatedly.
1091305bcbf0c961840c4505770d084a1caacc074dbbKenny Root         */
1092305bcbf0c961840c4505770d084a1caacc074dbbKenny Root        mConnector = new NativeDaemonConnector(this, "vold",
1093305bcbf0c961840c4505770d084a1caacc074dbbKenny Root                PackageManagerService.MAX_CONTAINERS * 2, VOLD_TAG);
1094207e538350665cea00e1aa70b8094beca4a34e45San Mehat        mReady = false;
1095305bcbf0c961840c4505770d084a1caacc074dbbKenny Root        Thread thread = new Thread(mConnector, VOLD_TAG);
1096207e538350665cea00e1aa70b8094beca4a34e45San Mehat        thread.start();
1097207e538350665cea00e1aa70b8094beca4a34e45San Mehat    }
1098207e538350665cea00e1aa70b8094beca4a34e45San Mehat
1099207e538350665cea00e1aa70b8094beca4a34e45San Mehat    /**
11004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * Exposed API calls below here
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
11027fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
11034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public void registerListener(IMountServiceListener listener) {
11044270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
11054270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            MountServiceBinderListener bl = new MountServiceBinderListener(listener);
11064270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            try {
11074270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                listener.asBinder().linkToDeath(bl, 0);
11084270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                mListeners.add(bl);
11094270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            } catch (RemoteException rex) {
1110a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to link to listener death");
11114270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
11127fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat        }
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public void unregisterListener(IMountServiceListener listener) {
11164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        synchronized (mListeners) {
11174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            for(MountServiceBinderListener bl : mListeners) {
11184270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                if (bl.mListener == listener) {
11194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    mListeners.remove(mListeners.indexOf(bl));
11204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                    return;
11214270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
11224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            }
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11266ffce2e9a3c57634bb73f8ff133ca680f8070d5dSuchi Amalapurapu    public void shutdown(final IMountShutdownObserver observer) {
11274270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.SHUTDOWN);
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1129a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        Slog.i(TAG, "Shutting down");
1130f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood        synchronized (mVolumeStates) {
1131f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            for (String path : mVolumeStates.keySet()) {
1132f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                String state = mVolumeStates.get(path);
1133f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood
1134f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                if (state.equals(Environment.MEDIA_SHARED)) {
1135f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    /*
1136f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * If the media is currently shared, unshare it.
1137f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * XXX: This is still dangerous!. We should not
1138f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * be rebooting at *all* if UMS is enabled, since
1139f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * the UMS host could have dirty FAT cache entries
1140f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * yet to flush.
1141f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     */
1142f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    setUsbMassStorageEnabled(false);
1143f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                } else if (state.equals(Environment.MEDIA_CHECKING)) {
1144f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    /*
1145f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * If the media is being checked, then we need to wait for
1146f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * it to complete before being able to proceed.
1147f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     */
1148f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    // XXX: @hackbod - Should we disable the ANR timer here?
1149f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    int retries = 30;
1150f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    while (state.equals(Environment.MEDIA_CHECKING) && (retries-- >=0)) {
1151f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        try {
1152f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                            Thread.sleep(1000);
1153f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        } catch (InterruptedException iex) {
1154f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                            Slog.e(TAG, "Interrupted while waiting for media", iex);
1155f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                            break;
1156f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        }
1157f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        state = Environment.getExternalStorageState();
1158f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    }
1159f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    if (retries == 0) {
1160f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        Slog.e(TAG, "Timed out waiting for media to check");
1161f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    }
11624270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                }
11637fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
1164f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                if (state.equals(Environment.MEDIA_MOUNTED)) {
1165f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    // Post a unmount message.
1166f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    ShutdownCallBack ucb = new ShutdownCallBack(path, observer);
1167f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
1168f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                } else if (observer != null) {
1169f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    /*
1170f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * Observer is waiting for onShutDownComplete when we are done.
1171f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * Since nothing will be done send notification directly so shutdown
1172f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     * sequence can continue.
1173f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                     */
1174f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    try {
1175f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        observer.onShutDownComplete(StorageResultCode.OperationSucceeded);
1176f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    } catch (RemoteException e) {
1177f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                        Slog.w(TAG, "RemoteException when shutting down");
1178f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                    }
1179f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                }
11805d0db4d356346bee68aec9a124df70dbaa9aaed1Johan Alfven            }
11811f6301e1ff1a8ba04bc2b9c55fe6ceb883ce43bfSan Mehat        }
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11840eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private boolean getUmsEnabling() {
11850eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        synchronized (mListeners) {
11860eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            return mUmsEnabling;
11870eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
11880eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
11890eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
11900eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    private void setUmsEnabling(boolean enable) {
11910eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        synchronized (mListeners) {
1192fc71125104650c61ab5b04f4c943de761d58cba6Tony Wu            mUmsEnabling = enable;
11930eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
11940eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    }
11950eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
1196b104340496e3a531e26c8f428c808eca0e039f50San Mehat    public boolean isUsbMassStorageConnected() {
1197207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
11987fd0fee968f4a3e474e1ea9933fc03552fe5f50aSan Mehat
11990eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (getUmsEnabling()) {
1200b104340496e3a531e26c8f428c808eca0e039f50San Mehat            return true;
1201b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
1202b104340496e3a531e26c8f428c808eca0e039f50San Mehat        return doGetShareMethodAvailable("ums");
12034270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12050eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu    public void setUsbMassStorageEnabled(boolean enable) {
1206207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
12070eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
12080eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu
12090eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        // TODO: Add support for multiple share methods
1210b104340496e3a531e26c8f428c808eca0e039f50San Mehat
12110eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        /*
12120eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         * If the volume is mounted and we're enabling then unmount it
12130eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         */
12140eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        String path = Environment.getExternalStorageDirectory().getPath();
12150eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        String vs = getVolumeState(path);
12160eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        String method = "ums";
12170eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
12180eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            // Override for isUsbMassStorageEnabled()
12190eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            setUmsEnabling(enable);
12200eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            UmsEnableCallBack umscb = new UmsEnableCallBack(path, method, true);
12210eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, umscb));
12220eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            // Clear override
12230eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            setUmsEnabling(false);
12240eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
12250eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        /*
12260eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         * If we disabled UMS then mount the volume
12270eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu         */
12280eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        if (!enable) {
12290eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            doShareUnshareVolume(path, method, enable);
12300eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            if (doMountVolume(path) != StorageResultCode.OperationSucceeded) {
1231a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                Slog.e(TAG, "Failed to remount " + path +
12320eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                        " after disabling share method " + method);
12330eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                /*
12340eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * Even though the mount failed, the unshare didn't so don't indicate an error.
12350eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * The mountVolume() call will have set the storage state and sent the necessary
12360eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 * broadcasts.
12370eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu                 */
12380eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu            }
12390eec21d97d9dc4eb4fdbad0e4c0fc53703452d02Suchi Amalapurapu        }
12404270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1242b104340496e3a531e26c8f428c808eca0e039f50San Mehat    public boolean isUsbMassStorageEnabled() {
1243207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1244b104340496e3a531e26c8f428c808eca0e039f50San Mehat        return doGetVolumeShared(Environment.getExternalStorageDirectory().getPath(), "ums");
12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12469ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat     * @return state of the volume at the specified mount point
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String getVolumeState(String mountPoint) {
1251f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood        synchronized (mVolumeStates) {
1252f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            String state = mVolumeStates.get(mountPoint);
1253f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            if (state == null) {
1254f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                Slog.w(TAG, "getVolumeState(" + mountPoint + "): Unknown volume");
1255f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood                throw new IllegalArgumentException();
1256f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            }
12574270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1258f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood            return state;
1259f097fc2fee57183508558acbca1f8742fb55615aMike Lockwood        }
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12614270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1262e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root    public boolean isExternalStorageEmulated() {
1263e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root        return mEmulateExternalStorage;
1264e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root    }
1265e1ff214e32ed5c546a7603b07b054908c4d93312Kenny Root
12664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int mountVolume(String path) {
12674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1269207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1270207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return doMountVolume(path);
12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1273c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu    public void unmountVolume(String path, boolean force) {
12744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1275207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12778a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        String volState = getVolumeState(path);
1278a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat        if (DEBUG_UNMOUNT) Slog.i(TAG, "Unmounting " + path + " force = " + force);
12798a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        if (Environment.MEDIA_UNMOUNTED.equals(volState) ||
12808a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_REMOVED.equals(volState) ||
12818a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_SHARED.equals(volState) ||
12828a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu                Environment.MEDIA_UNMOUNTABLE.equals(volState)) {
12838a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            // Media already unmounted or cannot be unmounted.
12848a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            // TODO return valid return code when adding observer call back.
12858a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu            return;
12868a9ab24a5c9b595ac0268fcade4b5bbfe7c45c2dSuchi Amalapurapu        }
1287c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        UnmountCallBack ucb = new UnmountCallBack(path, force);
1288c42e29e0a58d07a95d470780216cdf1d67476bd6Suchi Amalapurapu        mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
12894270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    }
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12914270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int formatVolume(String path) {
12924270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1293207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1295207e538350665cea00e1aa70b8094beca4a34e45San Mehat        return doFormatVolume(path);
12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12973697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1298c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat    public int []getStorageUsers(String path) {
1299c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1300c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        waitForReady();
1301c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        try {
1302c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            String[] r = mConnector.doListCommand(
1303c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                    String.format("storage users %s", path),
1304c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                            VoldResponseCode.StorageUsersListResult);
1305c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            // FMT: <pid> <process name>
1306c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            int[] data = new int[r.length];
1307c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            for (int i = 0; i < r.length; i++) {
1308c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                String []tok = r[i].split(" ");
1309c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                try {
1310c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                    data[i] = Integer.parseInt(tok[0]);
1311c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                } catch (NumberFormatException nfe) {
1312a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat                    Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
1313c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                    return new int[0];
1314c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat                }
1315c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            }
1316c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            return data;
1317c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        } catch (NativeDaemonConnectorException e) {
1318a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.e(TAG, "Failed to retrieve storage users list", e);
1319c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat            return new int[0];
1320c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat        }
1321c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat    }
1322c1b4ce93be60aa09eda5653edc2f6a8ce864526dSan Mehat
1323b104340496e3a531e26c8f428c808eca0e039f50San Mehat    private void warnOnNotMounted() {
1324b104340496e3a531e26c8f428c808eca0e039f50San Mehat        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
1325a50785979712bd45e4d122e7ef0e999732b15fcaSan Mehat            Slog.w(TAG, "getSecureContainerList() called when storage not mounted");
1326b104340496e3a531e26c8f428c808eca0e039f50San Mehat        }
1327b104340496e3a531e26c8f428c808eca0e039f50San Mehat    }
1328b104340496e3a531e26c8f428c808eca0e039f50San Mehat
13294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String[] getSecureContainerList() {
13304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
1331207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1332b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1333f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
13344270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
13354270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            return mConnector.doListCommand("asec list", VoldResponseCode.AsecListResult);
13364270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
13374270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            return new String[0];
133802735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
13393697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
13403697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
13414270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int createSecureContainer(String id, int sizeMb, String fstype,
13424270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat                                    String key, int ownerUid) {
13434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_CREATE);
1344207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1345b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
13464270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1347b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
13484270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        String cmd = String.format("asec create %s %d %s %s %d", id, sizeMb, fstype, key, ownerUid);
13494270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
13504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(cmd);
13514270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1352b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
135302735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1354a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1355a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        if (rc == StorageResultCode.OperationSucceeded) {
1356a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            synchronized (mAsecMountSet) {
1357a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                mAsecMountSet.add(id);
1358a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1359a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
13604270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
13613697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
13623697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
13634270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int finalizeSecureContainer(String id) {
13644270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_CREATE);
1365b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
13664270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1367b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
13684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
13694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(String.format("asec finalize %s", id));
1370a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            /*
1371a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             * Finalization does a remount, so no need
1372a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             * to update mAsecMountSet
1373a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat             */
13744270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1375b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
137602735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
13774270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
13783697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
13793697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1380d970998b0d489774ad1c5b94b47d233912f00214San Mehat    public int destroySecureContainer(String id, boolean force) {
13814270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_DESTROY);
1382207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1383b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1384f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
1385aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
1386aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
1387aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
1388aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
1389aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
1390aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
1391aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
1392aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
1393b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
13944270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
1395d970998b0d489774ad1c5b94b47d233912f00214San Mehat            mConnector.doCommand(String.format("asec destroy %s%s", id, (force ? " force" : "")));
13964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1397d970998b0d489774ad1c5b94b47d233912f00214San Mehat            int code = e.getCode();
1398d970998b0d489774ad1c5b94b47d233912f00214San Mehat            if (code == VoldResponseCode.OpFailedStorageBusy) {
1399d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedStorageBusy;
1400d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else {
1401d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedInternalError;
1402d970998b0d489774ad1c5b94b47d233912f00214San Mehat            }
140302735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1404a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1405a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        if (rc == StorageResultCode.OperationSucceeded) {
1406a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            synchronized (mAsecMountSet) {
1407a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                if (mAsecMountSet.contains(id)) {
1408a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                    mAsecMountSet.remove(id);
1409a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                }
1410a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1411a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1412a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
14134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
14143697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
14159ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
14164270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int mountSecureContainer(String id, String key, int ownerUid) {
14174270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
1418207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1419b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
14204270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1421a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        synchronized (mAsecMountSet) {
1422a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            if (mAsecMountSet.contains(id)) {
1423a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageMounted;
1424a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1425a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1426a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1427b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
14284270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        String cmd = String.format("asec mount %s %s %d", id, key, ownerUid);
14294270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
14304270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(cmd);
14314270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1432f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            int code = e.getCode();
1433f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            if (code != VoldResponseCode.OpFailedStorageBusy) {
1434f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root                rc = StorageResultCode.OperationFailedInternalError;
1435f030462c83a91432b7cf2c699778b63b1e79de72Kenny Root            }
143602735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
14376cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
14386cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        if (rc == StorageResultCode.OperationSucceeded) {
14396cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            synchronized (mAsecMountSet) {
14406cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat                mAsecMountSet.add(id);
14416cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
14426cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
14434270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
14443697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat    }
14453697229cc7adfd89493e87ba8b6401c8b68bdd71San Mehat
1446d970998b0d489774ad1c5b94b47d233912f00214San Mehat    public int unmountSecureContainer(String id, boolean force) {
14474270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
1448207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1449b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
14504270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
14516cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        synchronized (mAsecMountSet) {
14526cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            if (!mAsecMountSet.contains(id)) {
1453a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageNotMounted;
14546cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
14556cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat         }
14566cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
1457aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        /*
1458aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * Force a GC to make sure AssetManagers in other threads of the
1459aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * system_server are cleaned up. We have to do this since AssetManager
1460aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * instances are kept as a WeakReference and it's possible we have files
1461aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         * open on the external storage.
1462aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root         */
1463aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root        Runtime.getRuntime().gc();
1464aa48540222ef11115b29b8d7f2b7bd1ece772418Kenny Root
1465b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
1466d970998b0d489774ad1c5b94b47d233912f00214San Mehat        String cmd = String.format("asec unmount %s%s", id, (force ? " force" : ""));
14674270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
14684270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(cmd);
14694270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1470d970998b0d489774ad1c5b94b47d233912f00214San Mehat            int code = e.getCode();
1471d970998b0d489774ad1c5b94b47d233912f00214San Mehat            if (code == VoldResponseCode.OpFailedStorageBusy) {
1472d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedStorageBusy;
1473d970998b0d489774ad1c5b94b47d233912f00214San Mehat            } else {
1474d970998b0d489774ad1c5b94b47d233912f00214San Mehat                rc = StorageResultCode.OperationFailedInternalError;
1475d970998b0d489774ad1c5b94b47d233912f00214San Mehat            }
147602735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
14776cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
14786cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        if (rc == StorageResultCode.OperationSucceeded) {
14796cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            synchronized (mAsecMountSet) {
14806cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat                mAsecMountSet.remove(id);
14816cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            }
14826cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
14834270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
14849dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat    }
14859dba709d4439d8cdb464a3dcccbddffdbe4b10ffSan Mehat
14866cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    public boolean isSecureContainerMounted(String id) {
14876cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
14886cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        waitForReady();
14896cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        warnOnNotMounted();
14906cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
14916cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        synchronized (mAsecMountSet) {
14926cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat            return mAsecMountSet.contains(id);
14936cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat        }
14946cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat    }
14956cdd9c08565a6871ad72cd388adfdfca23532e5eSan Mehat
14964270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public int renameSecureContainer(String oldId, String newId) {
14974270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_RENAME);
1498207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1499b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
15004270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat
1501a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        synchronized (mAsecMountSet) {
150285451ee15fdf6cae371dc3005441988c7d426401San Mehat            /*
15039ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks             * Because a mounted container has active internal state which cannot be
150485451ee15fdf6cae371dc3005441988c7d426401San Mehat             * changed while active, we must ensure both ids are not currently mounted.
150585451ee15fdf6cae371dc3005441988c7d426401San Mehat             */
150685451ee15fdf6cae371dc3005441988c7d426401San Mehat            if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
1507a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat                return StorageResultCode.OperationFailedStorageMounted;
1508a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat            }
1509a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat        }
1510a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
1511b104340496e3a531e26c8f428c808eca0e039f50San Mehat        int rc = StorageResultCode.OperationSucceeded;
15124270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        String cmd = String.format("asec rename %s %s", oldId, newId);
15134270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        try {
15144270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat            mConnector.doCommand(cmd);
15154270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        } catch (NativeDaemonConnectorException e) {
1516b104340496e3a531e26c8f428c808eca0e039f50San Mehat            rc = StorageResultCode.OperationFailedInternalError;
151702735bc9b7686e56957cdec9c10660c4a6dd1090San Mehat        }
1518a181b21305e0bcf171e2112a3ca5c08eb4fd2434San Mehat
15194270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        return rc;
152045f61040823d8c442838f75cde8760f236603daeSan Mehat    }
152145f61040823d8c442838f75cde8760f236603daeSan Mehat
15224270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat    public String getSecureContainerPath(String id) {
15234270e1ea74c57f1c65620e9f5ecaa8c2a5daf0e1San Mehat        validatePermission(android.Manifest.permission.ASEC_ACCESS);
1524207e538350665cea00e1aa70b8094beca4a34e45San Mehat        waitForReady();
1525b104340496e3a531e26c8f428c808eca0e039f50San Mehat        warnOnNotMounted();
1526f919cd02dfd40ad1939e429c3f5e7e36538d839eSan Mehat
15272d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        try {
15282d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            ArrayList<String> rsp = mConnector.doCommand(String.format("asec path %s", id));
15292d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            String []tok = rsp.get(0).split(" ");
153022dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            int code = Integer.parseInt(tok[0]);
15312d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            if (code != VoldResponseCode.AsecPathResult) {
15322d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat                throw new IllegalStateException(String.format("Unexpected response code %d", code));
15332d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            }
15342d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            return tok[1];
15352d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat        } catch (NativeDaemonConnectorException e) {
15362d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            int code = e.getCode();
15372d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat            if (code == VoldResponseCode.OpFailedStorageNotFound) {
15382d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat                throw new IllegalArgumentException(String.format("Container '%s' not found", id));
153922dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            } else {
15402d66cef77e450ec4a4d725b89ae68c5e6b167beeSan Mehat                throw new IllegalStateException(String.format("Unexpected response code %d", code));
154122dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat            }
154222dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat        }
154322dd86e0556bf60f46bb92a4d90aef8c2d55da58San Mehat    }
1544e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu
1545e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu    public void finishMediaUpdate() {
1546e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu        mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
1547e99bb5f10b90736d10cee9729b56cba156fc0921Suchi Amalapurapu    }
154802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1549a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
1550a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        if (callerUid == android.os.Process.SYSTEM_UID) {
1551a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return true;
1552a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1553a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
155402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        if (packageName == null) {
155502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            return false;
155602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
155702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
155802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        final int packageUid = mPms.getPackageUid(packageName);
155902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
156002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        if (DEBUG_OBB) {
156102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
156202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root                    packageUid + ", callerUid = " + callerUid);
156302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
156402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
156502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        return callerUid == packageUid;
156602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
156702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
156802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    public String getMountedObbPath(String filename) {
1569af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (filename == null) {
1570af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("filename cannot be null");
1571af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        }
1572af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
157302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        waitForReady();
157402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        warnOnNotMounted();
157502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
157602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        try {
157702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            ArrayList<String> rsp = mConnector.doCommand(String.format("obb path %s", filename));
157802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            String []tok = rsp.get(0).split(" ");
157902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            int code = Integer.parseInt(tok[0]);
158002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            if (code != VoldResponseCode.AsecPathResult) {
158102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root                throw new IllegalStateException(String.format("Unexpected response code %d", code));
158202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
158302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            return tok[1];
158402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        } catch (NativeDaemonConnectorException e) {
158502c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            int code = e.getCode();
158602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            if (code == VoldResponseCode.OpFailedStorageNotFound) {
1587a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                return null;
158802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            } else {
158902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root                throw new IllegalStateException(String.format("Unexpected response code %d", code));
159002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
159102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
159202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
159302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
159402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    public boolean isObbMounted(String filename) {
1595af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (filename == null) {
1596af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("filename cannot be null");
1597af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        }
1598af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1599a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        synchronized (mObbMounts) {
1600af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            return mObbPathToStateMap.containsKey(filename);
1601a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1602a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
1603a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1604af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    public void mountObb(String filename, String key, IObbActionListener token, int nonce)
1605735de3b38abbd6564082a819377673ee593744a6Kenny Root            throws RemoteException {
1606f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root        if (filename == null) {
1607f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root            throw new IllegalArgumentException("filename cannot be null");
1608f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root        }
1609f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root
1610af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (token == null) {
1611af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw new IllegalArgumentException("token cannot be null");
16122942391801b79816c5eb77d7ac94c4a65f26af48Kenny Root        }
1613735de3b38abbd6564082a819377673ee593744a6Kenny Root
1614af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final int callerUid = Binder.getCallingUid();
1615af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final ObbState obbState = new ObbState(filename, callerUid, token, nonce);
1616af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final ObbAction action = new MountObbAction(obbState, key);
1617a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
1618a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1619a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        if (DEBUG_OBB)
1620a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            Slog.i(TAG, "Send to OBB handler: " + action.toString());
162102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
162202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1623af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    public void unmountObb(String filename, boolean force, IObbActionListener token, int nonce)
1624af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throws RemoteException {
1625f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root        if (filename == null) {
1626f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root            throw new IllegalArgumentException("filename cannot be null");
1627f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root        }
1628f1121dc1d35c7e8c317c278aad0dd4ad1358d870Kenny Root
1629af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final int callerUid = Binder.getCallingUid();
1630af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final ObbState obbState = new ObbState(filename, callerUid, token, nonce);
1631af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final ObbAction action = new UnmountObbAction(obbState, force);
1632a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
1633a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1634a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        if (DEBUG_OBB)
1635a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            Slog.i(TAG, "Send to OBB handler: " + action.toString());
1636a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
163702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
16385af0b916f850486cff4797355bf9e7dc3352fe00Jason parks    public int decryptStorage(String password) {
1639f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (TextUtils.isEmpty(password)) {
1640f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            throw new IllegalArgumentException("password cannot be empty");
16415af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        }
16425af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
16438888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
16448888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks                "no permission to access the crypt keeper");
16455af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
16465af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        waitForReady();
16475af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
16485af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        if (DEBUG_EVENTS) {
16495af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            Slog.i(TAG, "decrypting storage...");
16505af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        }
16515af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
16525af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        try {
16539ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            ArrayList<String> rsp = mConnector.doCommand("cryptfs checkpw " + password);
1654f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            String[] tokens = rsp.get(0).split(" ");
16559ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
1656f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            if (tokens == null || tokens.length != 2) {
16579ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                return -1;
16589ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            }
16599ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
1660f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            int code = Integer.parseInt(tokens[1]);
16619ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
16629ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            if (code == 0) {
16639ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                // Decrypt was successful. Post a delayed message before restarting in order
16649ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                // to let the UI to clear itself
16659ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                mHandler.postDelayed(new Runnable() {
16669ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                    public void run() {
16679ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                        mConnector.doCommand(String.format("cryptfs restart"));
16689ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks                    }
1669f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks                }, 1000); // 1 second
16709ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            }
16719ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks
16729ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            return code;
16735af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        } catch (NativeDaemonConnectorException e) {
16745af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            // Decryption failed
16755af0b916f850486cff4797355bf9e7dc3352fe00Jason parks            return e.getCode();
16765af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        }
16775af0b916f850486cff4797355bf9e7dc3352fe00Jason parks    }
16785af0b916f850486cff4797355bf9e7dc3352fe00Jason parks
167956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks    public int encryptStorage(String password) {
1680f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (TextUtils.isEmpty(password)) {
1681f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            throw new IllegalArgumentException("password cannot be empty");
168256aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        }
168356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
16848888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
16858888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks            "no permission to access the crypt keeper");
168656aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
168756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        waitForReady();
168856aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
168956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        if (DEBUG_EVENTS) {
16908888c597c4bc3002e48738b6aea6fd43f69c0f78Jason parks            Slog.i(TAG, "encrypting storage...");
169156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        }
169256aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
169356aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        try {
16949ed98bcdc9ef3445075fdba1933d0ec2b4bc147eJason parks            mConnector.doCommand(String.format("cryptfs enablecrypto inplace %s", password));
169556aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        } catch (NativeDaemonConnectorException e) {
169656aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks            // Encryption failed
169756aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks            return e.getCode();
169856aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        }
169956aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
170056aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks        return 0;
170156aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks    }
170256aa5321fe6f00fa3662e6f46a4b2559aa34f63eJason parks
1703f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks    public int changeEncryptionPassword(String password) {
1704f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (TextUtils.isEmpty(password)) {
1705f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            throw new IllegalArgumentException("password cannot be empty");
1706f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        }
1707f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1708f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
1709f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            "no permission to access the crypt keeper");
1710f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1711f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        waitForReady();
1712f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1713f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        if (DEBUG_EVENTS) {
1714f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            Slog.i(TAG, "changing encryption password...");
1715f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        }
1716f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1717f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        try {
1718f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            ArrayList<String> response = mConnector.doCommand("cryptfs changepw " + password);
1719f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1720f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            String[] tokens = response.get(0).split(" ");
1721f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1722f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            if (tokens == null || tokens.length != 2) {
1723f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks                return -1;
1724f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            }
1725f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1726f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            return Integer.parseInt(tokens[1]);
1727f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        } catch (NativeDaemonConnectorException e) {
1728f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            // Encryption failed
1729f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks            return e.getCode();
1730f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks        }
1731f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks    }
1732f7b3cd4efd40b7631f36ea014407a850f7dc637eJason parks
1733af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private void addObbStateLocked(ObbState obbState) throws RemoteException {
1734af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IBinder binder = obbState.getBinder();
1735af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        List<ObbState> obbStates = mObbMounts.get(binder);
17365919ac6b4188285324646772501ef4b97b353cf4Kenny Root
1737af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (obbStates == null) {
1738af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbStates = new ArrayList<ObbState>();
1739af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            mObbMounts.put(binder, obbStates);
1740af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        } else {
1741af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            for (final ObbState o : obbStates) {
1742af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (o.filename.equals(obbState.filename)) {
1743af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    throw new IllegalStateException("Attempt to add ObbState twice. "
1744af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            + "This indicates an error in the MountService logic.");
17455919ac6b4188285324646772501ef4b97b353cf4Kenny Root                }
17465919ac6b4188285324646772501ef4b97b353cf4Kenny Root            }
174702c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
174802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1749af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        obbStates.add(obbState);
1750af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        try {
1751af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbState.link();
1752af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        } catch (RemoteException e) {
1753af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            /*
1754af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * The binder died before we could link it, so clean up our state
1755af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * and return failure.
1756af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             */
1757af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            obbStates.remove(obbState);
1758af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.isEmpty()) {
1759af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mObbMounts.remove(binder);
176005105f7abe02b2dff91d6260b3628c8b97816babKenny Root            }
17615919ac6b4188285324646772501ef4b97b353cf4Kenny Root
1762af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            // Rethrow the error so mountObb can get it
1763af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            throw e;
176402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
1765af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1766af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        mObbPathToStateMap.put(obbState.filename, obbState);
1767a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
176802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1769af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root    private void removeObbStateLocked(ObbState obbState) {
1770af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final IBinder binder = obbState.getBinder();
1771af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        final List<ObbState> obbStates = mObbMounts.get(binder);
1772af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        if (obbStates != null) {
1773af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.remove(obbState)) {
1774af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                obbState.unlink();
1775af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
1776af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbStates.isEmpty()) {
1777af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mObbMounts.remove(binder);
1778af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
177938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
1780af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1781af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        mObbPathToStateMap.remove(obbState.filename);
178238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    }
178338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
1784a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    private class ObbActionHandler extends Handler {
1785a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private boolean mBound = false;
1786480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root        private final List<ObbAction> mActions = new LinkedList<ObbAction>();
1787a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1788a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbActionHandler(Looper l) {
1789a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(l);
1790a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1791a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1792a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
1793a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleMessage(Message msg) {
1794a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            switch (msg.what) {
1795a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_RUN_ACTION: {
1796480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                    final ObbAction action = (ObbAction) msg.obj;
1797a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1798a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
1799a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
1800a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1801a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // If a bind was already initiated we don't really
1802a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // need to do anything. The pending install
1803a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // will be processed later on.
1804a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (!mBound) {
1805a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // If this is the only one pending we might
1806a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // have to bind to the service again.
1807a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (!connectToService()) {
1808a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            Slog.e(TAG, "Failed to bind to media container service");
1809a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.handleError();
1810a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            return;
1811a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
1812a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
1813735de3b38abbd6564082a819377673ee593744a6Kenny Root
1814735de3b38abbd6564082a819377673ee593744a6Kenny Root                    mActions.add(action);
1815a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
1816a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
1817a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_BOUND: {
1818a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
1819a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_BOUND");
1820a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (msg.obj != null) {
1821a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mContainerService = (IMediaContainerService) msg.obj;
1822a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
1823a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mContainerService == null) {
1824a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Something seriously wrong. Bail out
1825a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.e(TAG, "Cannot bind to media container service");
1826a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        for (ObbAction action : mActions) {
1827a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            // Indicate service bind error
1828a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.handleError();
1829a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
1830a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mActions.clear();
1831a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else if (mActions.size() > 0) {
1832480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                        final ObbAction action = mActions.get(0);
1833a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (action != null) {
1834a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            action.execute(this);
1835a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
1836a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else {
1837a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Should never happen ideally.
1838a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.w(TAG, "Empty queue");
1839a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
1840a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
1841a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
1842a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_RECONNECT: {
1843a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
1844a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_RECONNECT");
1845a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() > 0) {
1846a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (mBound) {
1847a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            disconnectService();
1848a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
1849a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (!connectToService()) {
1850a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            Slog.e(TAG, "Failed to bind to media container service");
1851a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            for (ObbAction action : mActions) {
1852a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                                // Indicate service bind error
1853a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                                action.handleError();
1854a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            }
1855a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            mActions.clear();
1856a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
1857a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
1858a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
1859a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
1860a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                case OBB_MCS_UNBIND: {
1861a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
1862a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "OBB_MCS_UNBIND");
1863a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1864a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    // Delete pending install
1865a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() > 0) {
1866a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mActions.remove(0);
1867a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
1868a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (mActions.size() == 0) {
1869a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        if (mBound) {
1870a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                            disconnectService();
1871a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        }
1872a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    } else {
1873a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // There are more pending requests in queue.
1874a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // Just post MCS_BOUND message to trigger processing
1875a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        // of next pending install.
1876a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
1877a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    }
1878a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    break;
1879a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
1880af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                case OBB_FLUSH_MOUNT_STATE: {
1881af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    final String path = (String) msg.obj;
1882af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1883af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    if (DEBUG_OBB)
1884af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        Slog.i(TAG, "Flushing all OBB state for path " + path);
1885af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1886af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    synchronized (mObbMounts) {
1887af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
1888af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1889af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        final Iterator<Entry<String, ObbState>> i =
1890af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                mObbPathToStateMap.entrySet().iterator();
1891af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        while (i.hasNext()) {
1892af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            final Entry<String, ObbState> obbEntry = i.next();
1893af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1894af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            /*
1895af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * If this entry's source file is in the volume path
1896af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * that got unmounted, remove it because it's no
1897af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             * longer valid.
1898af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                             */
1899af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            if (obbEntry.getKey().startsWith(path)) {
1900af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                obbStatesToRemove.add(obbEntry.getValue());
1901af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            }
1902af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        }
1903af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1904af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        for (final ObbState obbState : obbStatesToRemove) {
1905af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            if (DEBUG_OBB)
1906af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                Slog.i(TAG, "Removing state for " + obbState.filename);
1907af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1908af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            removeObbStateLocked(obbState);
1909af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
1910af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            try {
1911af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                obbState.token.onObbResult(obbState.filename, obbState.nonce,
1912af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                        OnObbStateChangeListener.UNMOUNTED);
1913af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            } catch (RemoteException e) {
1914af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                Slog.i(TAG, "Couldn't send unmount notification for  OBB: "
1915af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                                        + obbState.filename);
1916af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                            }
1917af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        }
1918af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    }
1919af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    break;
1920af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                }
192102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
192202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
192302c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1924a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private boolean connectToService() {
1925a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (DEBUG_OBB)
1926a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                Slog.i(TAG, "Trying to bind to DefaultContainerService");
1927a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1928a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
1929a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) {
1930a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mBound = true;
1931a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                return true;
193202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
1933a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return false;
1934a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
1935a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1936a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private void disconnectService() {
1937a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mContainerService = null;
1938a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mBound = false;
1939a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mContext.unbindService(mDefContainerConn);
194002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
194102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
194202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1943a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    abstract class ObbAction {
1944a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private static final int MAX_RETRIES = 3;
1945a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private int mRetries;
194602c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1947a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbState mObbState;
1948a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
1949a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        ObbAction(ObbState obbState) {
1950a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mObbState = obbState;
195102c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
195202c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
1953a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void execute(ObbActionHandler handler) {
1954a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            try {
1955a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
1956a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.i(TAG, "Starting to execute action: " + this.toString());
1957a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mRetries++;
1958a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (mRetries > MAX_RETRIES) {
1959a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
1960480afe70fa75b74b618f1f6243e7e2be1f41419aKenny Root                    mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
1961a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    handleError();
1962a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    return;
1963a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                } else {
1964a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    handleExecute();
1965a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    if (DEBUG_OBB)
1966a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                        Slog.i(TAG, "Posting install MCS_UNBIND");
1967a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
1968a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
1969a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            } catch (RemoteException e) {
1970a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
1971a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.i(TAG, "Posting install MCS_RECONNECT");
1972a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
1973a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            } catch (Exception e) {
1974a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                if (DEBUG_OBB)
1975a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                    Slog.d(TAG, "Error handling OBB action", e);
1976a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                handleError();
197717eb6fb07cc6965f09c51adc70b3c291f57a784aKenny Root                mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
197802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
1979a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
198002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
198105105f7abe02b2dff91d6260b3628c8b97816babKenny Root        abstract void handleExecute() throws RemoteException, IOException;
1982a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        abstract void handleError();
198338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
198438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        protected ObbInfo getObbInfo() throws IOException {
198538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            ObbInfo obbInfo;
198638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            try {
198738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                obbInfo = mContainerService.getObbInfo(mObbState.filename);
198838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } catch (RemoteException e) {
198938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
199038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                        + mObbState.filename);
199138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                obbInfo = null;
199238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
199338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            if (obbInfo == null) {
199438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                throw new IOException("Couldn't read OBB file: " + mObbState.filename);
199538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
199638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return obbInfo;
199738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
199838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
1999af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root        protected void sendNewStatusOrIgnore(int status) {
2000af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (mObbState == null || mObbState.token == null) {
2001af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2002af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2003af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
200438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            try {
2005af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mObbState.token.onObbResult(mObbState.filename, mObbState.nonce, status);
200638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } catch (RemoteException e) {
200738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
200838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
200938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
2010a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
2011a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2012a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class MountObbAction extends ObbAction {
2013a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private String mKey;
2014a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2015a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        MountObbAction(ObbState obbState, String key) {
2016a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(obbState);
2017a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mKey = key;
2018a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2019a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
20205af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
2021735de3b38abbd6564082a819377673ee593744a6Kenny Root        public void handleExecute() throws IOException, RemoteException {
2022af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            waitForReady();
2023af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            warnOnNotMounted();
2024af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
202538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            final ObbInfo obbInfo = getObbInfo();
202638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2027af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mObbState.callerUid)) {
2028af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
2029af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        + " which is owned by " + obbInfo.packageName);
2030af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
2031af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2032af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2033af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2034af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final boolean isMounted;
2035af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            synchronized (mObbMounts) {
2036af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                isMounted = mObbPathToStateMap.containsKey(obbInfo.filename);
2037af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2038af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (isMounted) {
2039af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
2040af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
2041af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2042af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2043af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
204438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            /*
2045af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * The filename passed in might not be the canonical name, so just
2046af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root             * set the filename to the canonicalized version.
204738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root             */
2048af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            mObbState.filename = obbInfo.filename;
204938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2050af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final String hashedKey;
2051af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (mKey == null) {
2052af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                hashedKey = "none";
2053af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } else {
2054af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                try {
20553b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
20563b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root
20573b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
20583b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                            PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
20593b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    SecretKey key = factory.generateSecret(ks);
20603b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    BigInteger bi = new BigInteger(key.getEncoded());
20613b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    hashedKey = bi.toString(16);
2062af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } catch (NoSuchAlgorithmException e) {
20633b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
20643b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
20653b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    return;
20663b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                } catch (InvalidKeySpecException e) {
20673b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
20683b1abba6bbc895d63da3e82e9b158c01bd12edddKenny Root                    sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
2069af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    return;
207038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                }
2071a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
2072a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2073af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            int rc = StorageResultCode.OperationSucceeded;
2074af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            String cmd = String.format("obb mount %s %s %d", mObbState.filename, hashedKey,
2075af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    mObbState.callerUid);
2076af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            try {
2077af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mConnector.doCommand(cmd);
2078af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } catch (NativeDaemonConnectorException e) {
2079af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                int code = e.getCode();
2080af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (code != VoldResponseCode.OpFailedStorageBusy) {
2081af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedInternalError;
2082a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2083af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2084a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2085af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (rc == StorageResultCode.OperationSucceeded) {
2086af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (DEBUG_OBB)
2087af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    Slog.d(TAG, "Successfully mounted OBB " + mObbState.filename);
208838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2089af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                synchronized (mObbMounts) {
2090af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    addObbStateLocked(mObbState);
2091a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
209238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2093af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
209402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            } else {
209505105f7abe02b2dff91d6260b3628c8b97816babKenny Root                Slog.e(TAG, "Couldn't mount OBB file: " + rc);
2096a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2097af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
209802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root            }
209902c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
210002c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root
21015af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
2102a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleError() {
2103af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
210402c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root        }
2105a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2106a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
2107a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public String toString() {
2108a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            StringBuilder sb = new StringBuilder();
2109a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("MountObbAction{");
2110a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("filename=");
2111a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.filename);
2112a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",callerUid=");
2113a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.callerUid);
2114a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",token=");
2115a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.token != null ? mObbState.token.toString() : "NULL");
2116af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sb.append(",binder=");
2117af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sb.append(mObbState.token != null ? mObbState.getBinder().toString() : "null");
2118a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append('}');
2119a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return sb.toString();
2120a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2121a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    }
2122a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2123a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root    class UnmountObbAction extends ObbAction {
2124a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        private boolean mForceUnmount;
2125a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2126a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        UnmountObbAction(ObbState obbState, boolean force) {
2127a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            super(obbState);
2128a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            mForceUnmount = force;
2129a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2130a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
21315af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
213238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        public void handleExecute() throws IOException {
2133af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            waitForReady();
2134af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            warnOnNotMounted();
2135af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
213638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            final ObbInfo obbInfo = getObbInfo();
2137a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2138af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final ObbState obbState;
213938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            synchronized (mObbMounts) {
2140af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                obbState = mObbPathToStateMap.get(obbInfo.filename);
2141af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
214238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2143af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbState == null) {
2144af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
2145af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2146a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
2147a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2148af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (obbState.callerUid != mObbState.callerUid) {
2149af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Permission denied attempting to unmount OBB " + obbInfo.filename
2150af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                        + " (owned by " + obbInfo.packageName + ")");
2151af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
2152af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                return;
2153af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
2154a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2155af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            mObbState.filename = obbInfo.filename;
215638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2157af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            int rc = StorageResultCode.OperationSucceeded;
2158af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            String cmd = String.format("obb unmount %s%s", mObbState.filename,
2159af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    (mForceUnmount ? " force" : ""));
2160af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            try {
2161af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                mConnector.doCommand(cmd);
2162af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            } catch (NativeDaemonConnectorException e) {
2163af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                int code = e.getCode();
2164af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                if (code == VoldResponseCode.OpFailedStorageBusy) {
2165af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedStorageBusy;
2166af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
2167af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    // If it's not mounted then we've already won.
2168af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationSucceeded;
2169af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                } else {
2170af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    rc = StorageResultCode.OperationFailedInternalError;
2171a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root                }
2172a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            }
217338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2174af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            if (rc == StorageResultCode.OperationSucceeded) {
2175af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                synchronized (mObbMounts) {
2176af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    removeObbStateLocked(obbState);
2177af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                }
217838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2179af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
218038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            } else {
2181af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Slog.w(TAG, "Could not mount OBB: " + mObbState.filename);
2182af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
218338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
2184a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2185a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
21865af0b916f850486cff4797355bf9e7dc3352fe00Jason parks        @Override
2187a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public void handleError() {
2188af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
2189a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
2190a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root
2191a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        @Override
2192a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        public String toString() {
2193a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            StringBuilder sb = new StringBuilder();
2194a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("UnmountObbAction{");
2195a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append("filename=");
2196a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.filename != null ? mObbState.filename : "null");
2197a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",force=");
2198a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mForceUnmount);
2199a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",callerUid=");
2200a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.callerUid);
2201a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(",token=");
2202a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append(mObbState.token != null ? mObbState.token.toString() : "null");
2203735de3b38abbd6564082a819377673ee593744a6Kenny Root            sb.append(",binder=");
2204af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            sb.append(mObbState.token != null ? mObbState.getBinder().toString() : "null");
2205a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            sb.append('}');
2206a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root            return sb.toString();
2207a02b8b05dd1e8b8cf169e1f89542ef835b11fc13Kenny Root        }
220802c8730c1bf19daf48bec8c6995df676a00a73b1Kenny Root    }
220938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
221038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    @Override
221138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
221238cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) {
221338cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            pw.println("Permission Denial: can't dump ActivityManager from from pid="
221438cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
221538cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                    + " without permission " + android.Manifest.permission.DUMP);
221638cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            return;
221738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
221838cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
221938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        synchronized (mObbMounts) {
2220af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("  mObbMounts:");
222138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root
2222af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet().iterator();
2223af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            while (binders.hasNext()) {
2224af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                Entry<IBinder, List<ObbState>> e = binders.next();
2225af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print("    Key="); pw.println(e.getKey().toString());
2226af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                final List<ObbState> obbStates = e.getValue();
222738cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                for (final ObbState obbState : obbStates) {
2228af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                    pw.print("      "); pw.println(obbState.toString());
222938cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root                }
223038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root            }
2231af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root
2232af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("");
2233af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            pw.println("  mObbPathToStateMap:");
2234af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
2235af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            while (maps.hasNext()) {
2236af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                final Entry<String, ObbState> e = maps.next();
2237af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print("    "); pw.print(e.getKey());
2238af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root                pw.print(" -> "); pw.println(e.getValue().toString());
2239af9d667ccf3e24058214cf4cc0a8aa8bc5100e3cKenny Root            }
224038cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root        }
224138cf8867a8d3e8d5159abd0bd0e6a3b0b8348b94Kenny Root    }
22429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
22439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2244