MountService.java revision a31460ce1206ad938a809a2e19d51d2283398943
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.server;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport static com.android.internal.util.XmlUtils.readBooleanAttribute;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport static com.android.internal.util.XmlUtils.readIntAttribute;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport static com.android.internal.util.XmlUtils.readLongAttribute;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport static com.android.internal.util.XmlUtils.readStringAttribute;
231f5762e646bed2290934280464832782766ee68eMathias Agopianimport static com.android.internal.util.XmlUtils.writeBooleanAttribute;
248ae2335a3c93d0c00e998fdec18f64dfe43b94cbMathias Agopianimport static com.android.internal.util.XmlUtils.writeIntAttribute;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport static com.android.internal.util.XmlUtils.writeLongAttribute;
2655e3d60da5626752ffe1d15150d35ccb8fa644e7Mathias Agopianimport static com.android.internal.util.XmlUtils.writeStringAttribute;
2755e3d60da5626752ffe1d15150d35ccb8fa644e7Mathias Agopian
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport static org.xmlpull.v1.XmlPullParser.START_TAG;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.Manifest;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.annotation.Nullable;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.ActivityManager;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.ActivityManagerNative;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.AppOpsManager;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.IActivityManager;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ComponentName;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ServiceConnection;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.IPackageMoveObserver;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.ProviderInfo;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.UserInfo;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Configuration;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.ObbInfo;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.DropBoxManager;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Environment;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Environment.UserEnvironment;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.FileUtils;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.HandlerThread;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Looper;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ParcelFileDescriptor;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.PowerManager;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Process;
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteCallbackList;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ServiceManager;
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemProperties;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.UserHandle;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.UserManager;
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.storage.DiskInfo;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.storage.IMountService;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.storage.IMountServiceListener;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.storage.IMountShutdownObserver;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.storage.IObbActionListener;
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.storage.MountServiceInternal;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.storage.OnObbStateChangeListener;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.storage.StorageManager;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.storage.StorageResultCode;
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.storage.StorageVolume;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.storage.VolumeInfo;
815baa3a62a97544669fba6d65a11c07f252e654ddSteve Blockimport android.os.storage.VolumeRecord;
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.MediaStore;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils;
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.format.DateUtils;
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.ArrayMap;
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AtomicFile;
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Slog;
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.TimeUtils;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Xml;
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.annotations.GuardedBy;
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.app.IMediaContainerService;
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.os.SomeArgs;
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.os.Zygote;
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.util.ArrayUtils;
98e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissenimport com.android.internal.util.FastXmlSerializer;
995baa3a62a97544669fba6d65a11c07f252e654ddSteve Blockimport com.android.internal.util.HexDump;
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.util.IndentingPrintWriter;
101e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissenimport com.android.internal.util.Preconditions;
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.widget.LockPatternUtils;
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.server.NativeDaemonConnector.Command;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.server.NativeDaemonConnector.SensitiveArg;
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.server.pm.PackageManagerService;
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport libcore.io.IoUtils;
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport libcore.util.EmptyArray;
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParser;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParserException;
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlSerializer;
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File;
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileInputStream;
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileNotFoundException;
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileOutputStream;
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.math.BigInteger;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.nio.charset.StandardCharsets;
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.security.NoSuchAlgorithmException;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.security.spec.InvalidKeySpecException;
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.security.spec.KeySpec;
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays;
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashSet;
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Iterator;
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.LinkedList;
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List;
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Locale;
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map;
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map.Entry;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Objects;
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.CopyOnWriteArrayList;
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.CountDownLatch;
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.TimeUnit;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.TimeoutException;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.crypto.SecretKey;
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.crypto.SecretKeyFactory;
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport javax.crypto.spec.PBEKeySpec;
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Service responsible for various storage media. Connects to {@code vold} to
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * watch for and manage dynamically added storage, such as SD cards and USB mass
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * storage. Also decides how storage should be presented to users on the device.
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass MountService extends IMountService.Stub
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Static direct instance pointer for the tightly-coupled idle service to use
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static MountService sSelf = null;
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static class Lifecycle extends SystemService {
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private MountService mMountService;
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Lifecycle(Context context) {
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(context);
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onStart() {
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMountService = new MountService(getContext());
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            publishBinderService("mount", mMountService);
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMountService.start();
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onBootPhase(int phase) {
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mMountService.systemReady();
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mMountService.bootCompleted();
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onSwitchUser(int userHandle) {
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMountService.mCurrentUserId = userHandle;
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onUnlockUser(int userHandle) {
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMountService.onUnlockUser(userHandle);
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onCleanupUser(int userHandle) {
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMountService.onCleanupUser(userHandle);
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DEBUG_EVENTS = false;
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean DEBUG_OBB = false;
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Disable this since it messes up long-running cryptfs operations.
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final boolean WATCHDOG_ENABLE = false;
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "MountService";
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG_STORAGE_TRIM = "storage_trim";
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String VOLD_TAG = "VoldConnector";
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String CRYPTD_TAG = "CryptdConnector";
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Maximum number of ASEC containers allowed to be mounted. */
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MAX_CONTAINERS = 250;
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Magic value sent by MoveTask.cpp */
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MOVE_STATUS_COPY_FINISHED = 82;
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Internal vold response code constants
2185baa3a62a97544669fba6d65a11c07f252e654ddSteve Block     */
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class VoldResponseCode {
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * 100 series - Requestion action was initiated; expect another reply
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *              before proceeding with a new command.
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int VolumeListResult               = 110;
2255baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        public static final int AsecListResult                 = 111;
226e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        public static final int StorageUsersListResult         = 112;
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int CryptfsGetfieldResult          = 113;
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * 200 series - Requestion action has been successfully completed.
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int ShareStatusResult              = 210;
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int AsecPathResult                 = 211;
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int ShareEnabledResult             = 212;
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * 400 series - Command was accepted, but the requested action
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *              did not take place.
2395baa3a62a97544669fba6d65a11c07f252e654ddSteve Block         */
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int OpFailedNoMedia                = 401;
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int OpFailedMediaBlank             = 402;
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int OpFailedMediaCorrupt           = 403;
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int OpFailedVolNotMounted          = 404;
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int OpFailedStorageBusy            = 405;
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int OpFailedStorageNotFound        = 406;
2465baa3a62a97544669fba6d65a11c07f252e654ddSteve Block
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * 600 series - Unsolicited broadcasts.
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int DISK_CREATED = 640;
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int DISK_SIZE_CHANGED = 641;
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int DISK_LABEL_CHANGED = 642;
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int DISK_SCANNED = 643;
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int DISK_SYS_PATH_CHANGED = 644;
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int DISK_DESTROYED = 649;
25671f2cf116aab893e224056c38ab146bd1538dd3eSteve Block
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int VOLUME_CREATED = 650;
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int VOLUME_STATE_CHANGED = 651;
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int VOLUME_FS_TYPE_CHANGED = 652;
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int VOLUME_FS_UUID_CHANGED = 653;
2615baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        public static final int VOLUME_FS_LABEL_CHANGED = 654;
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int VOLUME_PATH_CHANGED = 655;
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int VOLUME_INTERNAL_PATH_CHANGED = 656;
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int VOLUME_DESTROYED = 659;
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int MOVE_STATUS = 660;
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int BENCHMARK_RESULT = 661;
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final int TRIM_RESULT = 662;
2695baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    }
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
271e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    private static final int VERSION_INIT = 1;
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int VERSION_ADD_PRIMARY = 2;
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int VERSION_FIX_PRIMARY = 3;
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG_VOLUMES = "volumes";
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String ATTR_VERSION = "version";
2775baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid";
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String ATTR_FORCE_ADOPTABLE = "forceAdoptable";
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG_VOLUME = "volume";
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String ATTR_TYPE = "type";
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String ATTR_FS_UUID = "fsUuid";
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String ATTR_PART_GUID = "partGuid";
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String ATTR_NICKNAME = "nickname";
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String ATTR_USER_FLAGS = "userFlags";
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String ATTR_CREATED_MILLIS = "createdMillis";
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis";
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis";
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final AtomicFile mSettingsFile;
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <em>Never</em> hold the lock while performing downcalls into vold, since
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * unsolicited events can suddenly appear to update data structures.
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Object mLock = new Object();
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2975baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    /** Set of users that we know are unlocked. */
298e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    @GuardedBy("mLock")
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int[] mLocalUnlockedUsers = EmptyArray.INT;
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Set of users that system knows are unlocked. */
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @GuardedBy("mLock")
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int[] mSystemUnlockedUsers = EmptyArray.INT;
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Map from disk ID to disk */
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @GuardedBy("mLock")
30671f2cf116aab893e224056c38ab146bd1538dd3eSteve Block    private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Map from volume ID to disk */
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @GuardedBy("mLock")
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Map from UUID to record */
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @GuardedBy("mLock")
3135baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>();
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @GuardedBy("mLock")
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private String mPrimaryStorageUuid;
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @GuardedBy("mLock")
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mForceAdoptable;
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Map from disk ID to latches */
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @GuardedBy("mLock")
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @GuardedBy("mLock")
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private IPackageMoveObserver mMoveCallback;
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @GuardedBy("mLock")
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private String mMoveTargetUuid;
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3285baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private VolumeInfo findVolumeByIdOrThrow(String id) {
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mLock) {
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final VolumeInfo vol = mVolumes.get(id);
3335baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            if (vol != null) {
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return vol;
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
33771f2cf116aab893e224056c38ab146bd1538dd3eSteve Block        throw new IllegalArgumentException("No volume found for ID " + id);
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private String findVolumeIdForPathOrThrow(String path) {
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mLock) {
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < mVolumes.size(); i++) {
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final VolumeInfo vol = mVolumes.valueAt(i);
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (vol.path != null && path.startsWith(vol.path)) {
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return vol.id;
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throw new IllegalArgumentException("No volume found for path " + path);
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private VolumeRecord findRecordForPath(String path) {
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mLock) {
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < mVolumes.size(); i++) {
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final VolumeInfo vol = mVolumes.valueAt(i);
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (vol.path != null && path.startsWith(vol.path)) {
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return mRecords.get(vol.fsUuid);
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private String scrubPath(String path) {
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (path.startsWith(Environment.getDataDirectory().getAbsolutePath())) {
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "internal";
367b3559643b946829933a76ed45750d13edfefad30Tor Norbye        }
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final VolumeRecord rec = findRecordForPath(path);
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (rec == null || rec.createdMillis == 0) {
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "unknown";
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "ext:" + (int) ((System.currentTimeMillis() - rec.createdMillis)
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    / DateUtils.WEEK_IN_MILLIS) + "w";
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private @Nullable VolumeInfo findStorageForUuid(String volumeUuid) {
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final StorageManager storage = mContext.getSystemService(StorageManager.class);
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL);
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return storage.getPrimaryPhysicalVolume();
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return storage.findEmulatedForPrivate(storage.findVolumeByUuid(volumeUuid));
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean shouldBenchmark() {
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final long benchInterval = Settings.Global.getLong(mContext.getContentResolver(),
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.Global.STORAGE_BENCHMARK_INTERVAL, DateUtils.WEEK_IN_MILLIS);
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (benchInterval == -1) {
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (benchInterval == 0) {
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mLock) {
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < mVolumes.size(); i++) {
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final VolumeInfo vol = mVolumes.valueAt(i);
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final VolumeRecord rec = mRecords.get(vol.fsUuid);
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (vol.isMountedWritable() && rec != null) {
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final long benchAge = System.currentTimeMillis() - rec.lastBenchMillis;
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (benchAge >= benchInterval) {
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        return true;
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private CountDownLatch findOrCreateDiskScanLatch(String diskId) {
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mLock) {
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            CountDownLatch latch = mDiskScanLatches.get(diskId);
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (latch == null) {
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                latch = new CountDownLatch(1);
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mDiskScanLatches.put(diskId, latch);
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4195baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            return latch;
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static String escapeNull(String arg) {
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (TextUtils.isEmpty(arg)) {
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "!";
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new IllegalArgumentException(arg);
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4305baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            return arg;
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** List of crypto types.
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project      * corresponding commands in CommandListener.cpp */
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final String[] CRYPTO_TYPES
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        = { "password", "default", "pattern", "pin" };
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Context mContext;
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final NativeDaemonConnector mConnector;
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final NativeDaemonConnector mCryptConnector;
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Thread mConnectorThread;
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Thread mCryptConnectorThread;
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private volatile boolean mSystemReady = false;
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private volatile boolean mBootCompleted = false;
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private volatile boolean mDaemonConnected = false;
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4525baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    private PackageManagerService mPms;
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Callbacks mCallbacks;
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final LockPatternUtils mLockPatternUtils;
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Two connectors - mConnector & mCryptConnector
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final CountDownLatch mConnectedSignal = new CountDownLatch(2);
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final CountDownLatch mAsecsScanned = new CountDownLatch(1);
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Object mUnmountLock = new Object();
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @GuardedBy("mUnmountLock")
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private CountDownLatch mUnmountSignal;
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Private hash of currently mounted secure containers.
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Used as a lock in methods to manipulate secure containers.
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final private HashSet<String> mAsecMountSet = new HashSet<String>();
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4715baa3a62a97544669fba6d65a11c07f252e654ddSteve Block    /**
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The size of the crypto algorithm key in bits for OBB files. Currently
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Twofish is used which takes 128-bit keys.
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4785baa3a62a97544669fba6d65a11c07f252e654ddSteve Block     * The number of times to run SHA1 in the PBKDF2 function for OBB files.
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * 1024 is reasonably secure and not too slow.
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int PBKDF2_HASH_ROUNDS = 1024;
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Mounted OBB tracking information. Used to track the current state of all
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * OBBs.
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Map from raw paths to {@link ObbState}. */
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Not guarded by a lock.
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final MountServiceInternalImpl mMountServiceInternal = new MountServiceInternalImpl();
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class ObbState implements IBinder.DeathRecipient {
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public ObbState(String rawPath, String canonicalPath, int callingUid,
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                IObbActionListener token, int nonce) {
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.rawPath = rawPath;
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.canonicalPath = canonicalPath;
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.ownerGid = UserHandle.getSharedAppGid(callingUid);
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.token = token;
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            this.nonce = nonce;
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final String rawPath;
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final String canonicalPath;
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int ownerGid;
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Token of remote Binder caller
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final IObbActionListener token;
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Identifier to pass back to the token
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int nonce;
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public IBinder getBinder() {
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return token.asBinder();
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void binderDied() {
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ObbAction action = new UnmountObbAction(this, true);
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void link() throws RemoteException {
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            getBinder().linkToDeath(this, 0);
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void unlink() {
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            getBinder().unlinkToDeath(this, 0);
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String toString() {
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            StringBuilder sb = new StringBuilder("ObbState{");
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append("rawPath=").append(rawPath);
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append(",canonicalPath=").append(canonicalPath);
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append(",ownerGid=").append(ownerGid);
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append(",token=").append(token);
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append(",binder=").append(getBinder());
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sb.append('}');
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return sb.toString();
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // OBB Action Handler
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final private ObbActionHandler mObbActionHandler;
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // OBB action handler messages
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int OBB_RUN_ACTION = 1;
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int OBB_MCS_BOUND = 2;
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int OBB_MCS_UNBIND = 3;
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int OBB_MCS_RECONNECT = 4;
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int OBB_FLUSH_MOUNT_STATE = 5;
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /*
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Default Container Service information
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class DefaultContainerConnection implements ServiceConnection {
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onServiceConnected(ComponentName name, IBinder service) {
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DEBUG_OBB)
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Slog.i(TAG, "onServiceConnected");
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onServiceDisconnected(ComponentName name) {
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (DEBUG_OBB)
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Slog.i(TAG, "onServiceDisconnected");
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Used in the ObbActionHandler
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private IMediaContainerService mContainerService = null;
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Last fstrim operation tracking
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String LAST_FSTRIM_FILE = "last-fstrim";
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final File mLastMaintenanceFile;
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private long mLastMaintenance;
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Handler messages
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int H_SYSTEM_READY = 1;
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int H_DAEMON_CONNECTED = 2;
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int H_SHUTDOWN = 3;
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int H_FSTRIM = 4;
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int H_VOLUME_MOUNT = 5;
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int H_VOLUME_BROADCAST = 6;
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int H_INTERNAL_BROADCAST = 7;
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int H_VOLUME_UNMOUNT = 8;
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int H_PARTITION_FORGET = 9;
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int H_RESET = 10;
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class MountServiceHandler extends Handler {
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public MountServiceHandler(Looper looper) {
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(looper);
6058564c8da817a845353d213acd8636b76f567b234Steve Block        }
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (msg.what) {
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case H_SYSTEM_READY: {
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    handleSystemReady();
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case H_DAEMON_CONNECTED: {
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    handleDaemonConnected();
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case H_FSTRIM: {
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!isReady()) {
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Slog.i(TAG, "fstrim requested, but no daemon connection yet; trying again");
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        sendMessageDelayed(obtainMessage(H_FSTRIM, msg.obj),
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                DateUtils.SECOND_IN_MILLIS);
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Slog.i(TAG, "Running fstrim idle maintenance");
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Remember when we kicked it off
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mLastMaintenance = System.currentTimeMillis();
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mLastMaintenanceFile.setLastModified(mLastMaintenance);
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (Exception e) {
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Slog.e(TAG, "Unable to record last fstrim!");
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final boolean shouldBenchmark = shouldBenchmark();
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // This method must be run on the main (handler) thread,
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // so it is safe to directly call into vold.
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mConnector.execute("fstrim", shouldBenchmark ? "dotrimbench" : "dotrim");
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (NativeDaemonConnectorException ndce) {
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Slog.e(TAG, "Failed to run fstrim!");
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // invoke the completion callback, if any
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // TODO: fstrim is non-blocking, so remove this useless callback
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Runnable callback = (Runnable) msg.obj;
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (callback != null) {
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        callback.run();
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case H_SHUTDOWN: {
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final IMountShutdownObserver obs = (IMountShutdownObserver) msg.obj;
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    boolean success = false;
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        success = mConnector.execute("volume", "shutdown").isClassOk();
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (NativeDaemonConnectorException ignored) {
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (obs != null) {
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        try {
6625baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                            obs.onShutDownComplete(success ? 0 : -1);
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } catch (RemoteException ignored) {
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case H_VOLUME_MOUNT: {
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final VolumeInfo vol = (VolumeInfo) msg.obj;
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (isMountDisallowed(vol)) {
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        break;
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    try {
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mConnector.execute("volume", "mount", vol.id, vol.mountFlags,
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                vol.mountUserId);
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } catch (NativeDaemonConnectorException ignored) {
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case H_VOLUME_UNMOUNT: {
6825baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                    final VolumeInfo vol = (VolumeInfo) msg.obj;
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    unmount(vol.getId());
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case H_VOLUME_BROADCAST: {
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final StorageVolume userVol = (StorageVolume) msg.obj;
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final String envState = userVol.getState();
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + envState + " to "
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            + userVol.getOwner());
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final String action = VolumeInfo.getBroadcastForEnvironment(envState);
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (action != null) {
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final Intent intent = new Intent(action,
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                Uri.fromFile(userVol.getPathFile()));
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, userVol);
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mContext.sendBroadcastAsUser(intent, userVol.getOwner());
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case H_INTERNAL_BROADCAST: {
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Internal broadcasts aimed at system components, not for
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // third-party apps.
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final Intent intent = (Intent) msg.obj;
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            android.Manifest.permission.WRITE_MEDIA_STORAGE);
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case H_PARTITION_FORGET: {
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final String partGuid = (String) msg.obj;
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    forgetPartition(partGuid);
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case H_RESET: {
7165baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                    resetIfReadyAndConnected();
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Handler mHandler;
7245baa3a62a97544669fba6d65a11c07f252e654ddSteve Block
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onReceive(Context context, Intent intent) {
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final String action = intent.getAction();
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Preconditions.checkArgument(userId >= 0);
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (Intent.ACTION_USER_ADDED.equals(action)) {
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final UserManager um = mContext.getSystemService(UserManager.class);
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final int userSerialNumber = um.getUserSerialNumber(userId);
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mConnector.execute("volume", "user_added", userId, userSerialNumber);
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    synchronized (mVolumes) {
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        final int size = mVolumes.size();
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        for (int i = 0; i < size; i++) {
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            final VolumeInfo vol = mVolumes.valueAt(i);
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (vol.mountUserId == userId) {
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                vol.mountUserId = UserHandle.USER_NULL;
744e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                                mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
745e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                            }
746e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                        }
747e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                    }
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mConnector.execute("volume", "user_removed", userId);
749e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                }
750e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            } catch (NativeDaemonConnectorException e) {
751e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                Slog.w(TAG, "Failed to send user details to vold", e);
752e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            }
753e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        }
754e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    };
755e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen
756e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    @Override
757e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    public void waitForAsecScan() {
758e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        waitForLatch(mAsecsScanned, "mAsecsScanned");
759e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    }
760e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen
761e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    private void waitForReady() {
762e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        waitForLatch(mConnectedSignal, "mConnectedSignal");
763e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    }
764e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen
765e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    private void waitForLatch(CountDownLatch latch, String condition) {
766e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        try {
767e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            waitForLatch(latch, condition, -1);
768e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        } catch (TimeoutException ignored) {
769e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        }
770e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    }
771e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen
772e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    private void waitForLatch(CountDownLatch latch, String condition, long timeoutMillis)
773e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            throws TimeoutException {
774e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        final long startMillis = SystemClock.elapsedRealtime();
775e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        while (true) {
776e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            try {
777e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                if (latch.await(5000, TimeUnit.MILLISECONDS)) {
778e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                    return;
779e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                } else {
7803762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                    Slog.w(TAG, "Thread " + Thread.currentThread().getName()
781e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                            + " still waiting for " + condition + "...");
782e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                }
7835baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            } catch (InterruptedException e) {
784e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                Slog.w(TAG, "Interrupt while waiting for " + condition);
785e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            }
786e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            if (timeoutMillis > 0 && SystemClock.elapsedRealtime() > startMillis + timeoutMillis) {
787e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                throw new TimeoutException("Thread " + Thread.currentThread().getName()
788e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                        + " gave up waiting for " + condition + " after " + timeoutMillis + "ms");
789e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            }
790e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        }
791e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    }
792e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen
793e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    private boolean isReady() {
794e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        try {
795e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            return mConnectedSignal.await(0, TimeUnit.MILLISECONDS);
796e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        } catch (InterruptedException e) {
797e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            return false;
798e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        }
79971f2cf116aab893e224056c38ab146bd1538dd3eSteve Block    }
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void handleSystemReady() {
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        initIfReadyAndConnected();
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        resetIfReadyAndConnected();
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Start scheduling nominally-daily fstrim operations
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MountServiceIdler.scheduleIdlePass(mContext);
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8085baa3a62a97544669fba6d65a11c07f252e654ddSteve Block
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * MediaProvider has a ton of code that makes assumptions about storage
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * paths never changing, so we outright kill them to pick up new state.
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
81371f2cf116aab893e224056c38ab146bd1538dd3eSteve Block    @Deprecated
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void killMediaProvider(List<UserInfo> users) {
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (users == null) return;
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final long token = Binder.clearCallingIdentity();
818e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        try {
819e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            for (UserInfo user : users) {
820e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                // System user does not have media provider, so skip.
821e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                if (user.isSystemOnly()) continue;
822e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen
823e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                final ProviderInfo provider = mPms.resolveContentProvider(MediaStore.AUTHORITY,
824e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                        PackageManager.MATCH_DIRECT_BOOT_AWARE
825e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
826e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                        user.id);
827e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                if (provider != null) {
828e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                    final IActivityManager am = ActivityManagerNative.getDefault();
829e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                    try {
830e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                        am.killApplicationWithAppId(provider.applicationInfo.packageName,
8315baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                                UserHandle.getAppId(provider.applicationInfo.uid), "vold reset");
832e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                        // We only need to run this once. It will kill all users' media processes.
833e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                        break;
834e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                    } catch (RemoteException e) {
835e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                    }
836e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                }
837e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            }
838e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        } finally {
839e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            Binder.restoreCallingIdentity(token);
84071f2cf116aab893e224056c38ab146bd1538dd3eSteve Block        }
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void addInternalVolumeLocked() {
8445baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        // Create a stub volume that represents internal storage
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
846e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                VolumeInfo.TYPE_PRIVATE, null, null);
847e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        internal.state = VolumeInfo.STATE_MOUNTED;
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        internal.path = Environment.getDataDirectory().getAbsolutePath();
849e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen        mVolumes.put(internal.id, internal);
850e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    }
851e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen
852e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen    private void initIfReadyAndConnected() {
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Slog.d(TAG, "Thinking about init, mSystemReady=" + mSystemReady
854e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                + ", mDaemonConnected=" + mDaemonConnected);
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mSystemReady && mDaemonConnected
856e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                && !StorageManager.isFileEncryptedNativeOnly()) {
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // When booting a device without native support, make sure that our
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // user directories are locked or unlocked based on the current
859e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            // emulation status.
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final boolean initLocked = StorageManager.isFileEncryptedEmulatedOnly();
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Slog.d(TAG, "Setting up emulation state, initlocked=" + initLocked);
862e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
863e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen            for (UserInfo user : users) {
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
865e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                    if (initLocked) {
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mCryptConnector.execute("cryptfs", "lock_user_key", user.id);
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mCryptConnector.execute("cryptfs", "unlock_user_key", user.id,
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                user.serialNumber, "!", "!");
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (NativeDaemonConnectorException e) {
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Slog.w(TAG, "Failed to init vold", e);
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void resetIfReadyAndConnected() {
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + ", mDaemonConnected=" + mDaemonConnected);
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mSystemReady && mDaemonConnected) {
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            killMediaProvider(users);
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int[] systemUnlockedUsers;
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mLock) {
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                systemUnlockedUsers = mSystemUnlockedUsers;
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mDisks.clear();
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mVolumes.clear();
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                addInternalVolumeLocked();
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mConnector.execute("volume", "reset");
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Tell vold about all existing and started users
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (UserInfo user : users) {
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mConnector.execute("volume", "user_added", user.id, user.serialNumber);
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (int userId : systemUnlockedUsers) {
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mConnector.execute("volume", "user_started", userId);
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (NativeDaemonConnectorException e) {
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Slog.w(TAG, "Failed to reset vold", e);
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void onUnlockUser(int userId) {
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Slog.d(TAG, "onUnlockUser " + userId);
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // We purposefully block here to make sure that user-specific
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // staging area is ready so it's ready for zygote-forked apps to
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // bind mount against.
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mConnector.execute("volume", "user_started", userId);
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (NativeDaemonConnectorException ignored) {
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Record user as started so newly mounted volumes kick off events
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // correctly, then synthesize events for any already-mounted volumes.
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mVolumes) {
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < mVolumes.size(); i++) {
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final VolumeInfo vol = mVolumes.valueAt(i);
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) {
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9318564c8da817a845353d213acd8636b76f567b234Steve Block                    final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSystemUnlockedUsers = ArrayUtils.appendInt(mSystemUnlockedUsers, userId);
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void onCleanupUser(int userId) {
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Slog.d(TAG, "onCleanupUser " + userId);
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mConnector.execute("volume", "user_stopped", userId);
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (NativeDaemonConnectorException ignored) {
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mVolumes) {
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void runIdleMaintenance(Runnable callback) {
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Binder entry point for kicking off an immediate fstrim
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void runMaintenance() {
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        runIdleMaintenance(null);
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public long lastMaintenance() {
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mLastMaintenance;
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Callback from NativeDaemonConnector
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onDaemonConnected() {
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mDaemonConnected = true;
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void handleDaemonConnected() {
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        initIfReadyAndConnected();
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        resetIfReadyAndConnected();
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Now that we've done our initialization, release
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * the hounds!
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mConnectedSignal.countDown();
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mConnectedSignal.getCount() != 0) {
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // More daemons need to connect
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // On an encrypted device we can't see system properties yet, so pull
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // the system locale out of the mount service.
9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ("".equals(SystemProperties.get("vold.encrypt_progress"))) {
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            copyLocaleFromMountService();
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Let package manager load internal ASECs.
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mPms.scanAvailableAsecs();
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Notify people waiting for ASECs to be scanned that it's done.
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAsecsScanned.countDown();
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void copyLocaleFromMountService() {
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String systemLocale;
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (RemoteException e) {
10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (TextUtils.isEmpty(systemLocale)) {
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Locale locale = Locale.forLanguageTag(systemLocale);
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Configuration config = new Configuration();
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        config.setLocale(locale);
10193762c311729fe9f3af085c14c5c1fb471d994c03Steve Block        try {
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ActivityManagerNative.getDefault().updatePersistentConfiguration(config);
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (RemoteException e) {
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Slog.e(TAG, "Error setting system locale from mount service", e);
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Temporary workaround for http://b/17945169.
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Callback from NativeDaemonConnector
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onCheckHoldWakeLock(int code) {
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Callback from NativeDaemonConnector
10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onEvent(int code, String raw, String[] cooked) {
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mLock) {
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return onEventLocked(code, raw, cooked);
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean onEventLocked(int code, String raw, String[] cooked) {
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (code) {
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case VoldResponseCode.DISK_CREATED: {
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (cooked.length != 3) break;
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final String id = cooked[1];
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int flags = Integer.parseInt(cooked[2]);
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false)
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        || mForceAdoptable) {
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    flags |= DiskInfo.FLAG_ADOPTABLE;
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mDisks.put(id, new DiskInfo(id, flags));
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10615baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            case VoldResponseCode.DISK_SIZE_CHANGED: {
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (cooked.length != 3) break;
10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final DiskInfo disk = mDisks.get(cooked[1]);
10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (disk != null) {
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    disk.size = Long.parseLong(cooked[2]);
10665baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                }
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case VoldResponseCode.DISK_LABEL_CHANGED: {
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final DiskInfo disk = mDisks.get(cooked[1]);
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (disk != null) {
10725baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                    final StringBuilder builder = new StringBuilder();
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    for (int i = 2; i < cooked.length; i++) {
10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        builder.append(cooked[i]).append(' ');
10759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    disk.label = builder.toString().trim();
10775baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                }
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case VoldResponseCode.DISK_SCANNED: {
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (cooked.length != 2) break;
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final DiskInfo disk = mDisks.get(cooked[1]);
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (disk != null) {
10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    onDiskScannedLocked(disk);
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case VoldResponseCode.DISK_SYS_PATH_CHANGED: {
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (cooked.length != 3) break;
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final DiskInfo disk = mDisks.get(cooked[1]);
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (disk != null) {
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    disk.sysPath = cooked[2];
10939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
10959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case VoldResponseCode.DISK_DESTROYED: {
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (cooked.length != 2) break;
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final DiskInfo disk = mDisks.remove(cooked[1]);
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (disk != null) {
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mCallbacks.notifyDiskDestroyed(disk);
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11045baa3a62a97544669fba6d65a11c07f252e654ddSteve Block
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case VoldResponseCode.VOLUME_CREATED: {
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final String id = cooked[1];
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int type = Integer.parseInt(cooked[2]);
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final String diskId = TextUtils.nullIfEmpty(cooked[3]);
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final String partGuid = TextUtils.nullIfEmpty(cooked[4]);
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final DiskInfo disk = mDisks.get(diskId);
11129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final VolumeInfo vol = new VolumeInfo(id, type, disk, partGuid);
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mVolumes.put(id, vol);
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                onVolumeCreatedLocked(vol);
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case VoldResponseCode.VOLUME_STATE_CHANGED: {
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (cooked.length != 3) break;
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final VolumeInfo vol = mVolumes.get(cooked[1]);
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (vol != null) {
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final int oldState = vol.state;
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final int newState = Integer.parseInt(cooked[2]);
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    vol.state = newState;
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    onVolumeStateChangedLocked(vol, oldState, newState);
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: {
11295baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                if (cooked.length != 3) break;
11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final VolumeInfo vol = mVolumes.get(cooked[1]);
11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (vol != null) {
11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    vol.fsType = cooked[2];
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (cooked.length != 3) break;
11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final VolumeInfo vol = mVolumes.get(cooked[1]);
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (vol != null) {
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    vol.fsUuid = cooked[2];
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final VolumeInfo vol = mVolumes.get(cooked[1]);
11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (vol != null) {
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    final StringBuilder builder = new StringBuilder();
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    for (int i = 2; i < cooked.length; i++) {
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        builder.append(cooked[i]).append(' ');
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    vol.fsLabel = builder.toString().trim();
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // TODO: notify listeners that label changed
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case VoldResponseCode.VOLUME_PATH_CHANGED: {
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (cooked.length != 3) break;
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final VolumeInfo vol = mVolumes.get(cooked[1]);
11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (vol != null) {
11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    vol.path = cooked[2];
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case VoldResponseCode.VOLUME_INTERNAL_PATH_CHANGED: {
11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (cooked.length != 3) break;
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final VolumeInfo vol = mVolumes.get(cooked[1]);
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (vol != null) {
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    vol.internalPath = cooked[2];
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case VoldResponseCode.VOLUME_DESTROYED: {
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (cooked.length != 2) break;
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mVolumes.remove(cooked[1]);
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case VoldResponseCode.MOVE_STATUS: {
11799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int status = Integer.parseInt(cooked[1]);
11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                onMoveStatusLocked(status);
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case VoldResponseCode.BENCHMARK_RESULT: {
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (cooked.length != 7) break;
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final String path = cooked[1];
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final String ident = cooked[2];
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final long create = Long.parseLong(cooked[3]);
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final long drop = Long.parseLong(cooked[4]);
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final long run = Long.parseLong(cooked[5]);
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final long destroy = Long.parseLong(cooked[6]);
11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + " " + ident + " " + create + " " + run + " " + destroy);
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final VolumeRecord rec = findRecordForPath(path);
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (rec != null) {
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    rec.lastBenchMillis = System.currentTimeMillis();
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    writeSettingsLocked();
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case VoldResponseCode.TRIM_RESULT: {
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (cooked.length != 4) break;
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final String path = cooked[1];
1207e38e90bf222515538281cc73c5e4a9f3c269c875Marco Nelissen                final long bytes = Long.parseLong(cooked[2]);
12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final long time = Long.parseLong(cooked[3]);
12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path)
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + " " + bytes + " " + time);
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final VolumeRecord rec = findRecordForPath(path);
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (rec != null) {
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    rec.lastTrimMillis = System.currentTimeMillis();
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    writeSettingsLocked();
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default: {
12245baa3a62a97544669fba6d65a11c07f252e654ddSteve Block                Slog.d(TAG, "Unhandled vold event " + code);
12259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void onDiskScannedLocked(DiskInfo disk) {
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int volumeCount = 0;
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < mVolumes.size(); i++) {
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final VolumeInfo vol = mVolumes.valueAt(i);
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (Objects.equals(disk.id, vol.getDiskId())) {
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                volumeCount++;
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
12455baa3a62a97544669fba6d65a11c07f252e654ddSteve Block        mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final CountDownLatch latch = mDiskScanLatches.remove(disk.id);
12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (latch != null) {
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            latch.countDown();
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        disk.volumeCount = volumeCount;
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mCallbacks.notifyDiskScanned(disk, volumeCount);
12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void onVolumeCreatedLocked(VolumeInfo vol) {
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mPms.isOnlyCoreApps()) {
12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId());
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (vol.type == VolumeInfo.TYPE_EMULATED) {
12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final StorageManager storage = mContext.getSystemService(StorageManager.class);
12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Slog.v(TAG, "Found primary storage at " + vol);
12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Slog.v(TAG, "Found primary storage at " + vol);
12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // TODO: only look at first public partition
12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    && vol.disk.isDefaultPrimary()) {
12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Slog.v(TAG, "Found primary storage at " + vol);
12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12885baa3a62a97544669fba6d65a11c07f252e654ddSteve Block
12895baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            // Adoptable public disks are visible to apps, since they meet
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // public API requirement of being in a stable location.
12915baa3a62a97544669fba6d65a11c07f252e654ddSteve Block            if (vol.disk.isAdoptable()) {
12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1295            vol.mountUserId = mCurrentUserId;
1296            mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1297
1298        } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1299            mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1300
1301        } else {
1302            Slog.d(TAG, "Skipping automatic mounting of " + vol);
1303        }
1304    }
1305
1306    private boolean isBroadcastWorthy(VolumeInfo vol) {
1307        switch (vol.getType()) {
1308            case VolumeInfo.TYPE_PRIVATE:
1309            case VolumeInfo.TYPE_PUBLIC:
1310            case VolumeInfo.TYPE_EMULATED:
1311                break;
1312            default:
1313                return false;
1314        }
1315
1316        switch (vol.getState()) {
1317            case VolumeInfo.STATE_MOUNTED:
1318            case VolumeInfo.STATE_MOUNTED_READ_ONLY:
1319            case VolumeInfo.STATE_EJECTING:
1320            case VolumeInfo.STATE_UNMOUNTED:
1321            case VolumeInfo.STATE_UNMOUNTABLE:
1322            case VolumeInfo.STATE_BAD_REMOVAL:
1323                break;
1324            default:
1325                return false;
1326        }
1327
1328        return true;
1329    }
1330
1331    private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
1332        // Remember that we saw this volume so we're ready to accept user
1333        // metadata, or so we can annoy them when a private volume is ejected
1334        if (vol.isMountedReadable() && !TextUtils.isEmpty(vol.fsUuid)) {
1335            VolumeRecord rec = mRecords.get(vol.fsUuid);
1336            if (rec == null) {
1337                rec = new VolumeRecord(vol.type, vol.fsUuid);
1338                rec.partGuid = vol.partGuid;
1339                rec.createdMillis = System.currentTimeMillis();
1340                if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1341                    rec.nickname = vol.disk.getDescription();
1342                }
1343                mRecords.put(rec.fsUuid, rec);
1344                writeSettingsLocked();
1345            } else {
1346                // Handle upgrade case where we didn't store partition GUID
1347                if (TextUtils.isEmpty(rec.partGuid)) {
1348                    rec.partGuid = vol.partGuid;
1349                    writeSettingsLocked();
1350                }
1351            }
1352        }
1353
1354        mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
1355
1356        // Do not broadcast before boot has completed to avoid launching the
1357        // processes that receive the intent unnecessarily.
1358        if (mBootCompleted && isBroadcastWorthy(vol)) {
1359            final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
1360            intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
1361            intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
1362            intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
1363            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1364                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
1365            mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
1366        }
1367
1368        final String oldStateEnv = VolumeInfo.getEnvironmentForState(oldState);
1369        final String newStateEnv = VolumeInfo.getEnvironmentForState(newState);
1370
1371        if (!Objects.equals(oldStateEnv, newStateEnv)) {
1372            // Kick state changed event towards all started users. Any users
1373            // started after this point will trigger additional
1374            // user-specific broadcasts.
1375            for (int userId : mSystemUnlockedUsers) {
1376                if (vol.isVisibleForRead(userId)) {
1377                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
1378                    mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
1379
1380                    mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
1381                            newStateEnv);
1382                }
1383            }
1384        }
1385
1386        if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.state == VolumeInfo.STATE_EJECTING) {
1387            // TODO: this should eventually be handled by new ObbVolume state changes
1388            /*
1389             * Some OBBs might have been unmounted when this volume was
1390             * unmounted, so send a message to the handler to let it know to
1391             * remove those from the list of mounted OBBS.
1392             */
1393            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
1394                    OBB_FLUSH_MOUNT_STATE, vol.path));
1395        }
1396    }
1397
1398    private void onMoveStatusLocked(int status) {
1399        if (mMoveCallback == null) {
1400            Slog.w(TAG, "Odd, status but no move requested");
1401            return;
1402        }
1403
1404        // TODO: estimate remaining time
1405        try {
1406            mMoveCallback.onStatusChanged(-1, status, -1);
1407        } catch (RemoteException ignored) {
1408        }
1409
1410        // We've finished copying and we're about to clean up old data, so
1411        // remember that move was successful if we get rebooted
1412        if (status == MOVE_STATUS_COPY_FINISHED) {
1413            Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
1414
1415            mPrimaryStorageUuid = mMoveTargetUuid;
1416            writeSettingsLocked();
1417        }
1418
1419        if (PackageManager.isMoveStatusFinished(status)) {
1420            Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status);
1421
1422            mMoveCallback = null;
1423            mMoveTargetUuid = null;
1424        }
1425    }
1426
1427    private void enforcePermission(String perm) {
1428        mContext.enforceCallingOrSelfPermission(perm, perm);
1429    }
1430
1431    /**
1432     * Decide if volume is mountable per device policies.
1433     */
1434    private boolean isMountDisallowed(VolumeInfo vol) {
1435        if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
1436            final UserManager userManager = mContext.getSystemService(UserManager.class);
1437            return userManager.hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
1438                    Binder.getCallingUserHandle());
1439        } else {
1440            return false;
1441        }
1442    }
1443
1444    private void enforceAdminUser() {
1445        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1446        final int callingUserId = UserHandle.getCallingUserId();
1447        boolean isAdmin;
1448        long token = Binder.clearCallingIdentity();
1449        try {
1450            isAdmin = um.getUserInfo(callingUserId).isAdmin();
1451        } finally {
1452            Binder.restoreCallingIdentity(token);
1453        }
1454        if (!isAdmin) {
1455            throw new SecurityException("Only admin users can adopt sd cards");
1456        }
1457    }
1458
1459    /**
1460     * Constructs a new MountService instance
1461     *
1462     * @param context  Binder context for this service
1463     */
1464    public MountService(Context context) {
1465        sSelf = this;
1466
1467        mContext = context;
1468        mCallbacks = new Callbacks(FgThread.get().getLooper());
1469        mLockPatternUtils = new LockPatternUtils(mContext);
1470
1471        // XXX: This will go away soon in favor of IMountServiceObserver
1472        mPms = (PackageManagerService) ServiceManager.getService("package");
1473
1474        HandlerThread hthread = new HandlerThread(TAG);
1475        hthread.start();
1476        mHandler = new MountServiceHandler(hthread.getLooper());
1477
1478        // Add OBB Action Handler to MountService thread.
1479        mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
1480
1481        // Initialize the last-fstrim tracking if necessary
1482        File dataDir = Environment.getDataDirectory();
1483        File systemDir = new File(dataDir, "system");
1484        mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
1485        if (!mLastMaintenanceFile.exists()) {
1486            // Not setting mLastMaintenance here means that we will force an
1487            // fstrim during reboot following the OTA that installs this code.
1488            try {
1489                (new FileOutputStream(mLastMaintenanceFile)).close();
1490            } catch (IOException e) {
1491                Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
1492            }
1493        } else {
1494            mLastMaintenance = mLastMaintenanceFile.lastModified();
1495        }
1496
1497        mSettingsFile = new AtomicFile(
1498                new File(Environment.getDataSystemDirectory(), "storage.xml"));
1499
1500        synchronized (mLock) {
1501            readSettingsLocked();
1502        }
1503
1504        LocalServices.addService(MountServiceInternal.class, mMountServiceInternal);
1505
1506        /*
1507         * Create the connection to vold with a maximum queue of twice the
1508         * amount of containers we'd ever expect to have. This keeps an
1509         * "asec list" from blocking a thread repeatedly.
1510         */
1511
1512        mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
1513                null);
1514        mConnector.setDebug(true);
1515        mConnector.setWarnIfHeld(mLock);
1516        mConnectorThread = new Thread(mConnector, VOLD_TAG);
1517
1518        // Reuse parameters from first connector since they are tested and safe
1519        mCryptConnector = new NativeDaemonConnector(this, "cryptd",
1520                MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
1521        mCryptConnector.setDebug(true);
1522        mCryptConnectorThread = new Thread(mCryptConnector, CRYPTD_TAG);
1523
1524        final IntentFilter userFilter = new IntentFilter();
1525        userFilter.addAction(Intent.ACTION_USER_ADDED);
1526        userFilter.addAction(Intent.ACTION_USER_REMOVED);
1527        mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
1528
1529        synchronized (mLock) {
1530            addInternalVolumeLocked();
1531        }
1532
1533        // Add ourself to the Watchdog monitors if enabled.
1534        if (WATCHDOG_ENABLE) {
1535            Watchdog.getInstance().addMonitor(this);
1536        }
1537    }
1538
1539    private void start() {
1540        mConnectorThread.start();
1541        mCryptConnectorThread.start();
1542    }
1543
1544    private void systemReady() {
1545        mSystemReady = true;
1546        mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
1547    }
1548
1549    private void bootCompleted() {
1550        mBootCompleted = true;
1551    }
1552
1553    private String getDefaultPrimaryStorageUuid() {
1554        if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) {
1555            return StorageManager.UUID_PRIMARY_PHYSICAL;
1556        } else {
1557            return StorageManager.UUID_PRIVATE_INTERNAL;
1558        }
1559    }
1560
1561    private void readSettingsLocked() {
1562        mRecords.clear();
1563        mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
1564        mForceAdoptable = false;
1565
1566        FileInputStream fis = null;
1567        try {
1568            fis = mSettingsFile.openRead();
1569            final XmlPullParser in = Xml.newPullParser();
1570            in.setInput(fis, StandardCharsets.UTF_8.name());
1571
1572            int type;
1573            while ((type = in.next()) != END_DOCUMENT) {
1574                if (type == START_TAG) {
1575                    final String tag = in.getName();
1576                    if (TAG_VOLUMES.equals(tag)) {
1577                        final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT);
1578                        final boolean primaryPhysical = SystemProperties.getBoolean(
1579                                StorageManager.PROP_PRIMARY_PHYSICAL, false);
1580                        final boolean validAttr = (version >= VERSION_FIX_PRIMARY)
1581                                || (version >= VERSION_ADD_PRIMARY && !primaryPhysical);
1582                        if (validAttr) {
1583                            mPrimaryStorageUuid = readStringAttribute(in,
1584                                    ATTR_PRIMARY_STORAGE_UUID);
1585                        }
1586                        mForceAdoptable = readBooleanAttribute(in, ATTR_FORCE_ADOPTABLE, false);
1587
1588                    } else if (TAG_VOLUME.equals(tag)) {
1589                        final VolumeRecord rec = readVolumeRecord(in);
1590                        mRecords.put(rec.fsUuid, rec);
1591                    }
1592                }
1593            }
1594        } catch (FileNotFoundException e) {
1595            // Missing metadata is okay, probably first boot
1596        } catch (IOException e) {
1597            Slog.wtf(TAG, "Failed reading metadata", e);
1598        } catch (XmlPullParserException e) {
1599            Slog.wtf(TAG, "Failed reading metadata", e);
1600        } finally {
1601            IoUtils.closeQuietly(fis);
1602        }
1603    }
1604
1605    private void writeSettingsLocked() {
1606        FileOutputStream fos = null;
1607        try {
1608            fos = mSettingsFile.startWrite();
1609
1610            XmlSerializer out = new FastXmlSerializer();
1611            out.setOutput(fos, StandardCharsets.UTF_8.name());
1612            out.startDocument(null, true);
1613            out.startTag(null, TAG_VOLUMES);
1614            writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
1615            writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
1616            writeBooleanAttribute(out, ATTR_FORCE_ADOPTABLE, mForceAdoptable);
1617            final int size = mRecords.size();
1618            for (int i = 0; i < size; i++) {
1619                final VolumeRecord rec = mRecords.valueAt(i);
1620                writeVolumeRecord(out, rec);
1621            }
1622            out.endTag(null, TAG_VOLUMES);
1623            out.endDocument();
1624
1625            mSettingsFile.finishWrite(fos);
1626        } catch (IOException e) {
1627            if (fos != null) {
1628                mSettingsFile.failWrite(fos);
1629            }
1630        }
1631    }
1632
1633    public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
1634        final int type = readIntAttribute(in, ATTR_TYPE);
1635        final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
1636        final VolumeRecord meta = new VolumeRecord(type, fsUuid);
1637        meta.partGuid = readStringAttribute(in, ATTR_PART_GUID);
1638        meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
1639        meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
1640        meta.createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
1641        meta.lastTrimMillis = readLongAttribute(in, ATTR_LAST_TRIM_MILLIS);
1642        meta.lastBenchMillis = readLongAttribute(in, ATTR_LAST_BENCH_MILLIS);
1643        return meta;
1644    }
1645
1646    public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
1647        out.startTag(null, TAG_VOLUME);
1648        writeIntAttribute(out, ATTR_TYPE, rec.type);
1649        writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
1650        writeStringAttribute(out, ATTR_PART_GUID, rec.partGuid);
1651        writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
1652        writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
1653        writeLongAttribute(out, ATTR_CREATED_MILLIS, rec.createdMillis);
1654        writeLongAttribute(out, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
1655        writeLongAttribute(out, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
1656        out.endTag(null, TAG_VOLUME);
1657    }
1658
1659    /**
1660     * Exposed API calls below here
1661     */
1662
1663    @Override
1664    public void registerListener(IMountServiceListener listener) {
1665        mCallbacks.register(listener);
1666    }
1667
1668    @Override
1669    public void unregisterListener(IMountServiceListener listener) {
1670        mCallbacks.unregister(listener);
1671    }
1672
1673    @Override
1674    public void shutdown(final IMountShutdownObserver observer) {
1675        enforcePermission(android.Manifest.permission.SHUTDOWN);
1676
1677        Slog.i(TAG, "Shutting down");
1678        mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
1679    }
1680
1681    @Override
1682    public boolean isUsbMassStorageConnected() {
1683        throw new UnsupportedOperationException();
1684    }
1685
1686    @Override
1687    public void setUsbMassStorageEnabled(boolean enable) {
1688        throw new UnsupportedOperationException();
1689    }
1690
1691    @Override
1692    public boolean isUsbMassStorageEnabled() {
1693        throw new UnsupportedOperationException();
1694    }
1695
1696    @Override
1697    public String getVolumeState(String mountPoint) {
1698        throw new UnsupportedOperationException();
1699    }
1700
1701    @Override
1702    public boolean isExternalStorageEmulated() {
1703        throw new UnsupportedOperationException();
1704    }
1705
1706    @Override
1707    public int mountVolume(String path) {
1708        mount(findVolumeIdForPathOrThrow(path));
1709        return 0;
1710    }
1711
1712    @Override
1713    public void unmountVolume(String path, boolean force, boolean removeEncryption) {
1714        unmount(findVolumeIdForPathOrThrow(path));
1715    }
1716
1717    @Override
1718    public int formatVolume(String path) {
1719        format(findVolumeIdForPathOrThrow(path));
1720        return 0;
1721    }
1722
1723    @Override
1724    public void mount(String volId) {
1725        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1726        waitForReady();
1727
1728        final VolumeInfo vol = findVolumeByIdOrThrow(volId);
1729        if (isMountDisallowed(vol)) {
1730            throw new SecurityException("Mounting " + volId + " restricted by policy");
1731        }
1732        try {
1733            mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId);
1734        } catch (NativeDaemonConnectorException e) {
1735            throw e.rethrowAsParcelableException();
1736        }
1737    }
1738
1739    @Override
1740    public void unmount(String volId) {
1741        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1742        waitForReady();
1743
1744        final VolumeInfo vol = findVolumeByIdOrThrow(volId);
1745
1746        // TODO: expand PMS to know about multiple volumes
1747        if (vol.isPrimaryPhysical()) {
1748            final long ident = Binder.clearCallingIdentity();
1749            try {
1750                synchronized (mUnmountLock) {
1751                    mUnmountSignal = new CountDownLatch(1);
1752                    mPms.updateExternalMediaStatus(false, true);
1753                    waitForLatch(mUnmountSignal, "mUnmountSignal");
1754                    mUnmountSignal = null;
1755                }
1756            } finally {
1757                Binder.restoreCallingIdentity(ident);
1758            }
1759        }
1760
1761        try {
1762            mConnector.execute("volume", "unmount", vol.id);
1763        } catch (NativeDaemonConnectorException e) {
1764            throw e.rethrowAsParcelableException();
1765        }
1766    }
1767
1768    @Override
1769    public void format(String volId) {
1770        enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1771        waitForReady();
1772
1773        final VolumeInfo vol = findVolumeByIdOrThrow(volId);
1774        try {
1775            mConnector.execute("volume", "format", vol.id, "auto");
1776        } catch (NativeDaemonConnectorException e) {
1777            throw e.rethrowAsParcelableException();
1778        }
1779    }
1780
1781    @Override
1782    public long benchmark(String volId) {
1783        enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1784        waitForReady();
1785
1786        try {
1787            // TODO: make benchmark async so we don't block other commands
1788            final NativeDaemonEvent res = mConnector.execute(3 * DateUtils.MINUTE_IN_MILLIS,
1789                    "volume", "benchmark", volId);
1790            return Long.parseLong(res.getMessage());
1791        } catch (NativeDaemonTimeoutException e) {
1792            return Long.MAX_VALUE;
1793        } catch (NativeDaemonConnectorException e) {
1794            throw e.rethrowAsParcelableException();
1795        }
1796    }
1797
1798    @Override
1799    public void partitionPublic(String diskId) {
1800        enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1801        waitForReady();
1802
1803        final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
1804        try {
1805            mConnector.execute("volume", "partition", diskId, "public");
1806            waitForLatch(latch, "partitionPublic", 3 * DateUtils.MINUTE_IN_MILLIS);
1807        } catch (NativeDaemonConnectorException e) {
1808            throw e.rethrowAsParcelableException();
1809        } catch (TimeoutException e) {
1810            throw new IllegalStateException(e);
1811        }
1812    }
1813
1814    @Override
1815    public void partitionPrivate(String diskId) {
1816        enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1817        enforceAdminUser();
1818        waitForReady();
1819
1820        final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
1821        try {
1822            mConnector.execute("volume", "partition", diskId, "private");
1823            waitForLatch(latch, "partitionPrivate", 3 * DateUtils.MINUTE_IN_MILLIS);
1824        } catch (NativeDaemonConnectorException e) {
1825            throw e.rethrowAsParcelableException();
1826        } catch (TimeoutException e) {
1827            throw new IllegalStateException(e);
1828        }
1829    }
1830
1831    @Override
1832    public void partitionMixed(String diskId, int ratio) {
1833        enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1834        enforceAdminUser();
1835        waitForReady();
1836
1837        final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
1838        try {
1839            mConnector.execute("volume", "partition", diskId, "mixed", ratio);
1840            waitForLatch(latch, "partitionMixed", 3 * DateUtils.MINUTE_IN_MILLIS);
1841        } catch (NativeDaemonConnectorException e) {
1842            throw e.rethrowAsParcelableException();
1843        } catch (TimeoutException e) {
1844            throw new IllegalStateException(e);
1845        }
1846    }
1847
1848    @Override
1849    public void setVolumeNickname(String fsUuid, String nickname) {
1850        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1851        waitForReady();
1852
1853        Preconditions.checkNotNull(fsUuid);
1854        synchronized (mLock) {
1855            final VolumeRecord rec = mRecords.get(fsUuid);
1856            rec.nickname = nickname;
1857            mCallbacks.notifyVolumeRecordChanged(rec);
1858            writeSettingsLocked();
1859        }
1860    }
1861
1862    @Override
1863    public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
1864        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1865        waitForReady();
1866
1867        Preconditions.checkNotNull(fsUuid);
1868        synchronized (mLock) {
1869            final VolumeRecord rec = mRecords.get(fsUuid);
1870            rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
1871            mCallbacks.notifyVolumeRecordChanged(rec);
1872            writeSettingsLocked();
1873        }
1874    }
1875
1876    @Override
1877    public void forgetVolume(String fsUuid) {
1878        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1879        waitForReady();
1880
1881        Preconditions.checkNotNull(fsUuid);
1882
1883        synchronized (mLock) {
1884            final VolumeRecord rec = mRecords.remove(fsUuid);
1885            if (rec != null && !TextUtils.isEmpty(rec.partGuid)) {
1886                mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
1887            }
1888            mCallbacks.notifyVolumeForgotten(fsUuid);
1889
1890            // If this had been primary storage, revert back to internal and
1891            // reset vold so we bind into new volume into place.
1892            if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
1893                mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
1894                mHandler.obtainMessage(H_RESET).sendToTarget();
1895            }
1896
1897            writeSettingsLocked();
1898        }
1899    }
1900
1901    @Override
1902    public void forgetAllVolumes() {
1903        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1904        waitForReady();
1905
1906        synchronized (mLock) {
1907            for (int i = 0; i < mRecords.size(); i++) {
1908                final String fsUuid = mRecords.keyAt(i);
1909                final VolumeRecord rec = mRecords.valueAt(i);
1910                if (!TextUtils.isEmpty(rec.partGuid)) {
1911                    mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
1912                }
1913                mCallbacks.notifyVolumeForgotten(fsUuid);
1914            }
1915            mRecords.clear();
1916
1917            if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)) {
1918                mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
1919            }
1920
1921            writeSettingsLocked();
1922            mHandler.obtainMessage(H_RESET).sendToTarget();
1923        }
1924    }
1925
1926    private void forgetPartition(String partGuid) {
1927        try {
1928            mConnector.execute("volume", "forget_partition", partGuid);
1929        } catch (NativeDaemonConnectorException e) {
1930            Slog.w(TAG, "Failed to forget key for " + partGuid + ": " + e);
1931        }
1932    }
1933
1934    private void remountUidExternalStorage(int uid, int mode) {
1935        waitForReady();
1936
1937        String modeName = "none";
1938        switch (mode) {
1939            case Zygote.MOUNT_EXTERNAL_DEFAULT: {
1940                modeName = "default";
1941            } break;
1942
1943            case Zygote.MOUNT_EXTERNAL_READ: {
1944                modeName = "read";
1945            } break;
1946
1947            case Zygote.MOUNT_EXTERNAL_WRITE: {
1948                modeName = "write";
1949            } break;
1950        }
1951
1952        try {
1953            mConnector.execute("volume", "remount_uid", uid, modeName);
1954        } catch (NativeDaemonConnectorException e) {
1955            Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e);
1956        }
1957    }
1958
1959    @Override
1960    public void setDebugFlags(int flags, int mask) {
1961        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1962        waitForReady();
1963
1964        if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
1965            if (StorageManager.isFileEncryptedNativeOnly()) {
1966                throw new IllegalStateException(
1967                        "Emulation not available on device with native FBE");
1968            }
1969            if (mLockPatternUtils.isCredentialRequiredToDecrypt(false)) {
1970                throw new IllegalStateException(
1971                        "Emulation requires disabling 'Secure start-up' in Settings > Security");
1972            }
1973
1974            final long token = Binder.clearCallingIdentity();
1975            try {
1976                final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
1977                SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
1978
1979                // Perform hard reboot to kick policy into place
1980                mContext.getSystemService(PowerManager.class).reboot(null);
1981            } finally {
1982                Binder.restoreCallingIdentity(token);
1983            }
1984        }
1985
1986        if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
1987            synchronized (mLock) {
1988                mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
1989
1990                writeSettingsLocked();
1991                mHandler.obtainMessage(H_RESET).sendToTarget();
1992            }
1993        }
1994
1995        if ((mask & (StorageManager.DEBUG_SDCARDFS_FORCE_ON
1996                | StorageManager.DEBUG_SDCARDFS_FORCE_OFF)) != 0) {
1997            final String value;
1998            if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_ON) != 0) {
1999                value = "force_on";
2000            } else if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_OFF) != 0) {
2001                value = "force_off";
2002            } else {
2003                value = "";
2004            }
2005
2006            final long token = Binder.clearCallingIdentity();
2007            try {
2008                SystemProperties.set(StorageManager.PROP_SDCARDFS, value);
2009
2010                // Reset storage to kick new setting into place
2011                mHandler.obtainMessage(H_RESET).sendToTarget();
2012            } finally {
2013                Binder.restoreCallingIdentity(token);
2014            }
2015        }
2016    }
2017
2018    @Override
2019    public String getPrimaryStorageUuid() {
2020        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2021        waitForReady();
2022
2023        synchronized (mLock) {
2024            return mPrimaryStorageUuid;
2025        }
2026    }
2027
2028    @Override
2029    public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
2030        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2031        waitForReady();
2032
2033        final VolumeInfo from;
2034        final VolumeInfo to;
2035
2036        synchronized (mLock) {
2037            if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) {
2038                throw new IllegalArgumentException("Primary storage already at " + volumeUuid);
2039            }
2040
2041            if (mMoveCallback != null) {
2042                throw new IllegalStateException("Move already in progress");
2043            }
2044            mMoveCallback = callback;
2045            mMoveTargetUuid = volumeUuid;
2046
2047            // When moving to/from primary physical volume, we probably just nuked
2048            // the current storage location, so we have nothing to move.
2049            if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
2050                    || Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
2051                Slog.d(TAG, "Skipping move to/from primary physical");
2052                onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
2053                onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
2054                mHandler.obtainMessage(H_RESET).sendToTarget();
2055                return;
2056
2057            } else {
2058                from = findStorageForUuid(mPrimaryStorageUuid);
2059                to = findStorageForUuid(volumeUuid);
2060
2061                if (from == null) {
2062                    Slog.w(TAG, "Failing move due to missing from volume " + mPrimaryStorageUuid);
2063                    onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2064                    return;
2065                } else if (to == null) {
2066                    Slog.w(TAG, "Failing move due to missing to volume " + volumeUuid);
2067                    onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2068                    return;
2069                }
2070            }
2071        }
2072
2073        try {
2074            mConnector.execute("volume", "move_storage", from.id, to.id);
2075        } catch (NativeDaemonConnectorException e) {
2076            throw e.rethrowAsParcelableException();
2077        }
2078    }
2079
2080    @Override
2081    public int[] getStorageUsers(String path) {
2082        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2083        waitForReady();
2084        try {
2085            final String[] r = NativeDaemonEvent.filterMessageList(
2086                    mConnector.executeForList("storage", "users", path),
2087                    VoldResponseCode.StorageUsersListResult);
2088
2089            // FMT: <pid> <process name>
2090            int[] data = new int[r.length];
2091            for (int i = 0; i < r.length; i++) {
2092                String[] tok = r[i].split(" ");
2093                try {
2094                    data[i] = Integer.parseInt(tok[0]);
2095                } catch (NumberFormatException nfe) {
2096                    Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
2097                    return new int[0];
2098                }
2099            }
2100            return data;
2101        } catch (NativeDaemonConnectorException e) {
2102            Slog.e(TAG, "Failed to retrieve storage users list", e);
2103            return new int[0];
2104        }
2105    }
2106
2107    private void warnOnNotMounted() {
2108        synchronized (mLock) {
2109            for (int i = 0; i < mVolumes.size(); i++) {
2110                final VolumeInfo vol = mVolumes.valueAt(i);
2111                if (vol.isPrimary() && vol.isMountedWritable()) {
2112                    // Cool beans, we have a mounted primary volume
2113                    return;
2114                }
2115            }
2116        }
2117
2118        Slog.w(TAG, "No primary storage mounted!");
2119    }
2120
2121    public String[] getSecureContainerList() {
2122        enforcePermission(android.Manifest.permission.ASEC_ACCESS);
2123        waitForReady();
2124        warnOnNotMounted();
2125
2126        try {
2127            return NativeDaemonEvent.filterMessageList(
2128                    mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
2129        } catch (NativeDaemonConnectorException e) {
2130            return new String[0];
2131        }
2132    }
2133
2134    public int createSecureContainer(String id, int sizeMb, String fstype, String key,
2135            int ownerUid, boolean external) {
2136        enforcePermission(android.Manifest.permission.ASEC_CREATE);
2137        waitForReady();
2138        warnOnNotMounted();
2139
2140        int rc = StorageResultCode.OperationSucceeded;
2141        try {
2142            mConnector.execute("asec", "create", id, sizeMb, fstype, new SensitiveArg(key),
2143                    ownerUid, external ? "1" : "0");
2144        } catch (NativeDaemonConnectorException e) {
2145            rc = StorageResultCode.OperationFailedInternalError;
2146        }
2147
2148        if (rc == StorageResultCode.OperationSucceeded) {
2149            synchronized (mAsecMountSet) {
2150                mAsecMountSet.add(id);
2151            }
2152        }
2153        return rc;
2154    }
2155
2156    @Override
2157    public int resizeSecureContainer(String id, int sizeMb, String key) {
2158        enforcePermission(android.Manifest.permission.ASEC_CREATE);
2159        waitForReady();
2160        warnOnNotMounted();
2161
2162        int rc = StorageResultCode.OperationSucceeded;
2163        try {
2164            mConnector.execute("asec", "resize", id, sizeMb, new SensitiveArg(key));
2165        } catch (NativeDaemonConnectorException e) {
2166            rc = StorageResultCode.OperationFailedInternalError;
2167        }
2168        return rc;
2169    }
2170
2171    public int finalizeSecureContainer(String id) {
2172        enforcePermission(android.Manifest.permission.ASEC_CREATE);
2173        warnOnNotMounted();
2174
2175        int rc = StorageResultCode.OperationSucceeded;
2176        try {
2177            mConnector.execute("asec", "finalize", id);
2178            /*
2179             * Finalization does a remount, so no need
2180             * to update mAsecMountSet
2181             */
2182        } catch (NativeDaemonConnectorException e) {
2183            rc = StorageResultCode.OperationFailedInternalError;
2184        }
2185        return rc;
2186    }
2187
2188    public int fixPermissionsSecureContainer(String id, int gid, String filename) {
2189        enforcePermission(android.Manifest.permission.ASEC_CREATE);
2190        warnOnNotMounted();
2191
2192        int rc = StorageResultCode.OperationSucceeded;
2193        try {
2194            mConnector.execute("asec", "fixperms", id, gid, filename);
2195            /*
2196             * Fix permissions does a remount, so no need to update
2197             * mAsecMountSet
2198             */
2199        } catch (NativeDaemonConnectorException e) {
2200            rc = StorageResultCode.OperationFailedInternalError;
2201        }
2202        return rc;
2203    }
2204
2205    public int destroySecureContainer(String id, boolean force) {
2206        enforcePermission(android.Manifest.permission.ASEC_DESTROY);
2207        waitForReady();
2208        warnOnNotMounted();
2209
2210        /*
2211         * Force a GC to make sure AssetManagers in other threads of the
2212         * system_server are cleaned up. We have to do this since AssetManager
2213         * instances are kept as a WeakReference and it's possible we have files
2214         * open on the external storage.
2215         */
2216        Runtime.getRuntime().gc();
2217
2218        int rc = StorageResultCode.OperationSucceeded;
2219        try {
2220            final Command cmd = new Command("asec", "destroy", id);
2221            if (force) {
2222                cmd.appendArg("force");
2223            }
2224            mConnector.execute(cmd);
2225        } catch (NativeDaemonConnectorException e) {
2226            int code = e.getCode();
2227            if (code == VoldResponseCode.OpFailedStorageBusy) {
2228                rc = StorageResultCode.OperationFailedStorageBusy;
2229            } else {
2230                rc = StorageResultCode.OperationFailedInternalError;
2231            }
2232        }
2233
2234        if (rc == StorageResultCode.OperationSucceeded) {
2235            synchronized (mAsecMountSet) {
2236                if (mAsecMountSet.contains(id)) {
2237                    mAsecMountSet.remove(id);
2238                }
2239            }
2240        }
2241
2242        return rc;
2243    }
2244
2245    public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) {
2246        enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
2247        waitForReady();
2248        warnOnNotMounted();
2249
2250        synchronized (mAsecMountSet) {
2251            if (mAsecMountSet.contains(id)) {
2252                return StorageResultCode.OperationFailedStorageMounted;
2253            }
2254        }
2255
2256        int rc = StorageResultCode.OperationSucceeded;
2257        try {
2258            mConnector.execute("asec", "mount", id, new SensitiveArg(key), ownerUid,
2259                    readOnly ? "ro" : "rw");
2260        } catch (NativeDaemonConnectorException e) {
2261            int code = e.getCode();
2262            if (code != VoldResponseCode.OpFailedStorageBusy) {
2263                rc = StorageResultCode.OperationFailedInternalError;
2264            }
2265        }
2266
2267        if (rc == StorageResultCode.OperationSucceeded) {
2268            synchronized (mAsecMountSet) {
2269                mAsecMountSet.add(id);
2270            }
2271        }
2272        return rc;
2273    }
2274
2275    public int unmountSecureContainer(String id, boolean force) {
2276        enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
2277        waitForReady();
2278        warnOnNotMounted();
2279
2280        synchronized (mAsecMountSet) {
2281            if (!mAsecMountSet.contains(id)) {
2282                return StorageResultCode.OperationFailedStorageNotMounted;
2283            }
2284         }
2285
2286        /*
2287         * Force a GC to make sure AssetManagers in other threads of the
2288         * system_server are cleaned up. We have to do this since AssetManager
2289         * instances are kept as a WeakReference and it's possible we have files
2290         * open on the external storage.
2291         */
2292        Runtime.getRuntime().gc();
2293
2294        int rc = StorageResultCode.OperationSucceeded;
2295        try {
2296            final Command cmd = new Command("asec", "unmount", id);
2297            if (force) {
2298                cmd.appendArg("force");
2299            }
2300            mConnector.execute(cmd);
2301        } catch (NativeDaemonConnectorException e) {
2302            int code = e.getCode();
2303            if (code == VoldResponseCode.OpFailedStorageBusy) {
2304                rc = StorageResultCode.OperationFailedStorageBusy;
2305            } else {
2306                rc = StorageResultCode.OperationFailedInternalError;
2307            }
2308        }
2309
2310        if (rc == StorageResultCode.OperationSucceeded) {
2311            synchronized (mAsecMountSet) {
2312                mAsecMountSet.remove(id);
2313            }
2314        }
2315        return rc;
2316    }
2317
2318    public boolean isSecureContainerMounted(String id) {
2319        enforcePermission(android.Manifest.permission.ASEC_ACCESS);
2320        waitForReady();
2321        warnOnNotMounted();
2322
2323        synchronized (mAsecMountSet) {
2324            return mAsecMountSet.contains(id);
2325        }
2326    }
2327
2328    public int renameSecureContainer(String oldId, String newId) {
2329        enforcePermission(android.Manifest.permission.ASEC_RENAME);
2330        waitForReady();
2331        warnOnNotMounted();
2332
2333        synchronized (mAsecMountSet) {
2334            /*
2335             * Because a mounted container has active internal state which cannot be
2336             * changed while active, we must ensure both ids are not currently mounted.
2337             */
2338            if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
2339                return StorageResultCode.OperationFailedStorageMounted;
2340            }
2341        }
2342
2343        int rc = StorageResultCode.OperationSucceeded;
2344        try {
2345            mConnector.execute("asec", "rename", oldId, newId);
2346        } catch (NativeDaemonConnectorException e) {
2347            rc = StorageResultCode.OperationFailedInternalError;
2348        }
2349
2350        return rc;
2351    }
2352
2353    public String getSecureContainerPath(String id) {
2354        enforcePermission(android.Manifest.permission.ASEC_ACCESS);
2355        waitForReady();
2356        warnOnNotMounted();
2357
2358        final NativeDaemonEvent event;
2359        try {
2360            event = mConnector.execute("asec", "path", id);
2361            event.checkCode(VoldResponseCode.AsecPathResult);
2362            return event.getMessage();
2363        } catch (NativeDaemonConnectorException e) {
2364            int code = e.getCode();
2365            if (code == VoldResponseCode.OpFailedStorageNotFound) {
2366                Slog.i(TAG, String.format("Container '%s' not found", id));
2367                return null;
2368            } else {
2369                throw new IllegalStateException(String.format("Unexpected response code %d", code));
2370            }
2371        }
2372    }
2373
2374    public String getSecureContainerFilesystemPath(String id) {
2375        enforcePermission(android.Manifest.permission.ASEC_ACCESS);
2376        waitForReady();
2377        warnOnNotMounted();
2378
2379        final NativeDaemonEvent event;
2380        try {
2381            event = mConnector.execute("asec", "fspath", id);
2382            event.checkCode(VoldResponseCode.AsecPathResult);
2383            return event.getMessage();
2384        } catch (NativeDaemonConnectorException e) {
2385            int code = e.getCode();
2386            if (code == VoldResponseCode.OpFailedStorageNotFound) {
2387                Slog.i(TAG, String.format("Container '%s' not found", id));
2388                return null;
2389            } else {
2390                throw new IllegalStateException(String.format("Unexpected response code %d", code));
2391            }
2392        }
2393    }
2394
2395    @Override
2396    public void finishMediaUpdate() {
2397        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
2398            throw new SecurityException("no permission to call finishMediaUpdate()");
2399        }
2400        if (mUnmountSignal != null) {
2401            mUnmountSignal.countDown();
2402        } else {
2403            Slog.w(TAG, "Odd, nobody asked to unmount?");
2404        }
2405    }
2406
2407    private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
2408        if (callerUid == android.os.Process.SYSTEM_UID) {
2409            return true;
2410        }
2411
2412        if (packageName == null) {
2413            return false;
2414        }
2415
2416        final int packageUid = mPms.getPackageUid(packageName,
2417                PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callerUid));
2418
2419        if (DEBUG_OBB) {
2420            Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
2421                    packageUid + ", callerUid = " + callerUid);
2422        }
2423
2424        return callerUid == packageUid;
2425    }
2426
2427    public String getMountedObbPath(String rawPath) {
2428        Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2429
2430        waitForReady();
2431        warnOnNotMounted();
2432
2433        final ObbState state;
2434        synchronized (mObbMounts) {
2435            state = mObbPathToStateMap.get(rawPath);
2436        }
2437        if (state == null) {
2438            Slog.w(TAG, "Failed to find OBB mounted at " + rawPath);
2439            return null;
2440        }
2441
2442        final NativeDaemonEvent event;
2443        try {
2444            event = mConnector.execute("obb", "path", state.canonicalPath);
2445            event.checkCode(VoldResponseCode.AsecPathResult);
2446            return event.getMessage();
2447        } catch (NativeDaemonConnectorException e) {
2448            int code = e.getCode();
2449            if (code == VoldResponseCode.OpFailedStorageNotFound) {
2450                return null;
2451            } else {
2452                throw new IllegalStateException(String.format("Unexpected response code %d", code));
2453            }
2454        }
2455    }
2456
2457    @Override
2458    public boolean isObbMounted(String rawPath) {
2459        Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2460        synchronized (mObbMounts) {
2461            return mObbPathToStateMap.containsKey(rawPath);
2462        }
2463    }
2464
2465    @Override
2466    public void mountObb(
2467            String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) {
2468        Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2469        Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
2470        Preconditions.checkNotNull(token, "token cannot be null");
2471
2472        final int callingUid = Binder.getCallingUid();
2473        final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce);
2474        final ObbAction action = new MountObbAction(obbState, key, callingUid);
2475        mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
2476
2477        if (DEBUG_OBB)
2478            Slog.i(TAG, "Send to OBB handler: " + action.toString());
2479    }
2480
2481    @Override
2482    public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
2483        Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2484
2485        final ObbState existingState;
2486        synchronized (mObbMounts) {
2487            existingState = mObbPathToStateMap.get(rawPath);
2488        }
2489
2490        if (existingState != null) {
2491            // TODO: separate state object from request data
2492            final int callingUid = Binder.getCallingUid();
2493            final ObbState newState = new ObbState(
2494                    rawPath, existingState.canonicalPath, callingUid, token, nonce);
2495            final ObbAction action = new UnmountObbAction(newState, force);
2496            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
2497
2498            if (DEBUG_OBB)
2499                Slog.i(TAG, "Send to OBB handler: " + action.toString());
2500        } else {
2501            Slog.w(TAG, "Unknown OBB mount at " + rawPath);
2502        }
2503    }
2504
2505    @Override
2506    public int getEncryptionState() {
2507        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2508                "no permission to access the crypt keeper");
2509
2510        waitForReady();
2511
2512        final NativeDaemonEvent event;
2513        try {
2514            event = mCryptConnector.execute("cryptfs", "cryptocomplete");
2515            return Integer.parseInt(event.getMessage());
2516        } catch (NumberFormatException e) {
2517            // Bad result - unexpected.
2518            Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
2519            return ENCRYPTION_STATE_ERROR_UNKNOWN;
2520        } catch (NativeDaemonConnectorException e) {
2521            // Something bad happened.
2522            Slog.w(TAG, "Error in communicating with cryptfs in validating");
2523            return ENCRYPTION_STATE_ERROR_UNKNOWN;
2524        }
2525    }
2526
2527    @Override
2528    public int decryptStorage(String password) {
2529        if (TextUtils.isEmpty(password)) {
2530            throw new IllegalArgumentException("password cannot be empty");
2531        }
2532
2533        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2534                "no permission to access the crypt keeper");
2535
2536        waitForReady();
2537
2538        if (DEBUG_EVENTS) {
2539            Slog.i(TAG, "decrypting storage...");
2540        }
2541
2542        final NativeDaemonEvent event;
2543        try {
2544            event = mCryptConnector.execute("cryptfs", "checkpw", new SensitiveArg(password));
2545
2546            final int code = Integer.parseInt(event.getMessage());
2547            if (code == 0) {
2548                // Decrypt was successful. Post a delayed message before restarting in order
2549                // to let the UI to clear itself
2550                mHandler.postDelayed(new Runnable() {
2551                    public void run() {
2552                        try {
2553                            mCryptConnector.execute("cryptfs", "restart");
2554                        } catch (NativeDaemonConnectorException e) {
2555                            Slog.e(TAG, "problem executing in background", e);
2556                        }
2557                    }
2558                }, 1000); // 1 second
2559            }
2560
2561            return code;
2562        } catch (NativeDaemonConnectorException e) {
2563            // Decryption failed
2564            return e.getCode();
2565        }
2566    }
2567
2568    public int encryptStorage(int type, String password) {
2569        if (TextUtils.isEmpty(password) && type != StorageManager.CRYPT_TYPE_DEFAULT) {
2570            throw new IllegalArgumentException("password cannot be empty");
2571        }
2572
2573        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2574            "no permission to access the crypt keeper");
2575
2576        waitForReady();
2577
2578        if (DEBUG_EVENTS) {
2579            Slog.i(TAG, "encrypting storage...");
2580        }
2581
2582        try {
2583            if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
2584                mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2585                                CRYPTO_TYPES[type]);
2586            } else {
2587                mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2588                                CRYPTO_TYPES[type], new SensitiveArg(password));
2589            }
2590        } catch (NativeDaemonConnectorException e) {
2591            // Encryption failed
2592            return e.getCode();
2593        }
2594
2595        return 0;
2596    }
2597
2598    /** Set the password for encrypting the master key.
2599     *  @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
2600     *  @param password The password to set.
2601     */
2602    public int changeEncryptionPassword(int type, String password) {
2603        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2604            "no permission to access the crypt keeper");
2605
2606        waitForReady();
2607
2608        if (DEBUG_EVENTS) {
2609            Slog.i(TAG, "changing encryption password...");
2610        }
2611
2612        try {
2613            NativeDaemonEvent event = mCryptConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type],
2614                        new SensitiveArg(password));
2615            return Integer.parseInt(event.getMessage());
2616        } catch (NativeDaemonConnectorException e) {
2617            // Encryption failed
2618            return e.getCode();
2619        }
2620    }
2621
2622    /**
2623     * Validate a user-supplied password string with cryptfs
2624     */
2625    @Override
2626    public int verifyEncryptionPassword(String password) throws RemoteException {
2627        // Only the system process is permitted to validate passwords
2628        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2629            throw new SecurityException("no permission to access the crypt keeper");
2630        }
2631
2632        mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2633            "no permission to access the crypt keeper");
2634
2635        if (TextUtils.isEmpty(password)) {
2636            throw new IllegalArgumentException("password cannot be empty");
2637        }
2638
2639        waitForReady();
2640
2641        if (DEBUG_EVENTS) {
2642            Slog.i(TAG, "validating encryption password...");
2643        }
2644
2645        final NativeDaemonEvent event;
2646        try {
2647            event = mCryptConnector.execute("cryptfs", "verifypw", new SensitiveArg(password));
2648            Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
2649            return Integer.parseInt(event.getMessage());
2650        } catch (NativeDaemonConnectorException e) {
2651            // Encryption failed
2652            return e.getCode();
2653        }
2654    }
2655
2656    /**
2657     * Get the type of encryption used to encrypt the master key.
2658     * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
2659     */
2660    @Override
2661    public int getPasswordType() {
2662        mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2663            "no permission to access the crypt keeper");
2664
2665        waitForReady();
2666
2667        final NativeDaemonEvent event;
2668        try {
2669            event = mCryptConnector.execute("cryptfs", "getpwtype");
2670            for (int i = 0; i < CRYPTO_TYPES.length; ++i) {
2671                if (CRYPTO_TYPES[i].equals(event.getMessage()))
2672                    return i;
2673            }
2674
2675            throw new IllegalStateException("unexpected return from cryptfs");
2676        } catch (NativeDaemonConnectorException e) {
2677            throw e.rethrowAsParcelableException();
2678        }
2679    }
2680
2681    /**
2682     * Set a field in the crypto header.
2683     * @param field field to set
2684     * @param contents contents to set in field
2685     */
2686    @Override
2687    public void setField(String field, String contents) throws RemoteException {
2688        mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2689            "no permission to access the crypt keeper");
2690
2691        waitForReady();
2692
2693        final NativeDaemonEvent event;
2694        try {
2695            event = mCryptConnector.execute("cryptfs", "setfield", field, contents);
2696        } catch (NativeDaemonConnectorException e) {
2697            throw e.rethrowAsParcelableException();
2698        }
2699    }
2700
2701    /**
2702     * Gets a field from the crypto header.
2703     * @param field field to get
2704     * @return contents of field
2705     */
2706    @Override
2707    public String getField(String field) throws RemoteException {
2708        mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2709            "no permission to access the crypt keeper");
2710
2711        waitForReady();
2712
2713        final NativeDaemonEvent event;
2714        try {
2715            final String[] contents = NativeDaemonEvent.filterMessageList(
2716                    mCryptConnector.executeForList("cryptfs", "getfield", field),
2717                    VoldResponseCode.CryptfsGetfieldResult);
2718            String result = new String();
2719            for (String content : contents) {
2720                result += content;
2721            }
2722            return result;
2723        } catch (NativeDaemonConnectorException e) {
2724            throw e.rethrowAsParcelableException();
2725        }
2726    }
2727
2728    /**
2729     * Is userdata convertible to file based encryption?
2730     * @return non zero for convertible
2731     */
2732    @Override
2733    public boolean isConvertibleToFBE() throws RemoteException {
2734        mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2735            "no permission to access the crypt keeper");
2736
2737        waitForReady();
2738
2739        final NativeDaemonEvent event;
2740        try {
2741            event = mCryptConnector.execute("cryptfs", "isConvertibleToFBE");
2742            return Integer.parseInt(event.getMessage()) != 0;
2743        } catch (NativeDaemonConnectorException e) {
2744            throw e.rethrowAsParcelableException();
2745        }
2746    }
2747
2748    @Override
2749    public String getPassword() throws RemoteException {
2750        mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2751                "only keyguard can retrieve password");
2752
2753        if (!isReady()) {
2754            return new String();
2755        }
2756
2757        final NativeDaemonEvent event;
2758        try {
2759            event = mCryptConnector.execute("cryptfs", "getpw");
2760            if ("-1".equals(event.getMessage())) {
2761                // -1 equals no password
2762                return null;
2763            }
2764            return event.getMessage();
2765        } catch (NativeDaemonConnectorException e) {
2766            throw e.rethrowAsParcelableException();
2767        } catch (IllegalArgumentException e) {
2768            Slog.e(TAG, "Invalid response to getPassword");
2769            return null;
2770        }
2771    }
2772
2773    @Override
2774    public void clearPassword() throws RemoteException {
2775        mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2776                "only keyguard can clear password");
2777
2778        if (!isReady()) {
2779            return;
2780        }
2781
2782        final NativeDaemonEvent event;
2783        try {
2784            event = mCryptConnector.execute("cryptfs", "clearpw");
2785        } catch (NativeDaemonConnectorException e) {
2786            throw e.rethrowAsParcelableException();
2787        }
2788    }
2789
2790    @Override
2791    public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
2792        enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2793        waitForReady();
2794
2795        try {
2796            mCryptConnector.execute("cryptfs", "create_user_key", userId, serialNumber,
2797                ephemeral ? 1 : 0);
2798        } catch (NativeDaemonConnectorException e) {
2799            throw e.rethrowAsParcelableException();
2800        }
2801    }
2802
2803    @Override
2804    public void destroyUserKey(int userId) {
2805        enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2806        waitForReady();
2807
2808        try {
2809            mCryptConnector.execute("cryptfs", "destroy_user_key", userId);
2810        } catch (NativeDaemonConnectorException e) {
2811            throw e.rethrowAsParcelableException();
2812        }
2813    }
2814
2815    private SensitiveArg encodeBytes(byte[] bytes) {
2816        if (ArrayUtils.isEmpty(bytes)) {
2817            return new SensitiveArg("!");
2818        } else {
2819            return new SensitiveArg(HexDump.toHexString(bytes));
2820        }
2821    }
2822
2823    /*
2824     * Add this token/secret pair to the set of ways we can recover a disk encryption key.
2825     * Changing the token/secret for a disk encryption key is done in two phases: first, adding
2826     * a new token/secret pair with this call, then delting all other pairs with
2827     * fixateNewestUserKeyAuth. This allows other places where a credential is used, such as
2828     * Gatekeeper, to be updated between the two calls.
2829     */
2830    @Override
2831    public void addUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
2832        enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2833        waitForReady();
2834
2835        try {
2836            mCryptConnector.execute("cryptfs", "add_user_key_auth", userId, serialNumber,
2837                encodeBytes(token), encodeBytes(secret));
2838        } catch (NativeDaemonConnectorException e) {
2839            throw e.rethrowAsParcelableException();
2840        }
2841    }
2842
2843    /*
2844     * Delete all disk encryption token/secret pairs except the most recently added one
2845     */
2846    @Override
2847    public void fixateNewestUserKeyAuth(int userId) {
2848        enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2849        waitForReady();
2850
2851        try {
2852            mCryptConnector.execute("cryptfs", "fixate_newest_user_key_auth", userId);
2853        } catch (NativeDaemonConnectorException e) {
2854            throw e.rethrowAsParcelableException();
2855        }
2856    }
2857
2858    @Override
2859    public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
2860        enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2861        waitForReady();
2862
2863        if (StorageManager.isFileEncryptedNativeOrEmulated()) {
2864            // When a user has secure lock screen, require a challenge token to
2865            // actually unlock. This check is mostly in place for emulation mode.
2866            if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(token)) {
2867                throw new IllegalStateException("Token required to unlock secure user " + userId);
2868            }
2869
2870            try {
2871                mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber,
2872                        encodeBytes(token), encodeBytes(secret));
2873            } catch (NativeDaemonConnectorException e) {
2874                throw e.rethrowAsParcelableException();
2875            }
2876        }
2877
2878        synchronized (mLock) {
2879            mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId);
2880        }
2881    }
2882
2883    @Override
2884    public void lockUserKey(int userId) {
2885        enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2886        waitForReady();
2887
2888        try {
2889            mCryptConnector.execute("cryptfs", "lock_user_key", userId);
2890        } catch (NativeDaemonConnectorException e) {
2891            throw e.rethrowAsParcelableException();
2892        }
2893
2894        synchronized (mLock) {
2895            mLocalUnlockedUsers = ArrayUtils.removeInt(mLocalUnlockedUsers, userId);
2896        }
2897    }
2898
2899    @Override
2900    public boolean isUserKeyUnlocked(int userId) {
2901        synchronized (mLock) {
2902            return ArrayUtils.contains(mLocalUnlockedUsers, userId);
2903        }
2904    }
2905
2906    @Override
2907    public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
2908        enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2909        waitForReady();
2910
2911        try {
2912            mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid),
2913                    userId, serialNumber, flags);
2914        } catch (NativeDaemonConnectorException e) {
2915            throw e.rethrowAsParcelableException();
2916        }
2917    }
2918
2919    @Override
2920    public void destroyUserStorage(String volumeUuid, int userId, int flags) {
2921        enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2922        waitForReady();
2923
2924        try {
2925            mCryptConnector.execute("cryptfs", "destroy_user_storage", escapeNull(volumeUuid),
2926                    userId, flags);
2927        } catch (NativeDaemonConnectorException e) {
2928            throw e.rethrowAsParcelableException();
2929        }
2930    }
2931
2932    @Override
2933    public ParcelFileDescriptor mountAppFuse(final String name) throws RemoteException {
2934        try {
2935            final int uid = Binder.getCallingUid();
2936            final int pid = Binder.getCallingPid();
2937            final NativeDaemonEvent event =
2938                    mConnector.execute("appfuse", "mount", uid, pid, name);
2939            if (event.getFileDescriptors() == null) {
2940                throw new RemoteException("AppFuse FD from vold is null.");
2941            }
2942            return ParcelFileDescriptor.fromFd(
2943                    event.getFileDescriptors()[0],
2944                    mHandler,
2945                    new ParcelFileDescriptor.OnCloseListener() {
2946                        @Override
2947                        public void onClose(IOException e) {
2948                            try {
2949                                final NativeDaemonEvent event = mConnector.execute(
2950                                        "appfuse", "unmount", uid, pid, name);
2951                            } catch (NativeDaemonConnectorException unmountException) {
2952                                Log.e(TAG, "Failed to unmount appfuse.");
2953                            }
2954                        }
2955                    });
2956        } catch (NativeDaemonConnectorException e) {
2957            throw e.rethrowAsParcelableException();
2958        } catch (IOException e) {
2959            throw new RemoteException(e.getMessage());
2960        }
2961    }
2962
2963    @Override
2964    public int mkdirs(String callingPkg, String appPath) {
2965        final int userId = UserHandle.getUserId(Binder.getCallingUid());
2966        final UserEnvironment userEnv = new UserEnvironment(userId);
2967
2968        // Validate that reported package name belongs to caller
2969        final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
2970                Context.APP_OPS_SERVICE);
2971        appOps.checkPackage(Binder.getCallingUid(), callingPkg);
2972
2973        File appFile = null;
2974        try {
2975            appFile = new File(appPath).getCanonicalFile();
2976        } catch (IOException e) {
2977            Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
2978            return -1;
2979        }
2980
2981        // Try translating the app path into a vold path, but require that it
2982        // belong to the calling package.
2983        if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) ||
2984                FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) ||
2985                FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) {
2986            appPath = appFile.getAbsolutePath();
2987            if (!appPath.endsWith("/")) {
2988                appPath = appPath + "/";
2989            }
2990
2991            try {
2992                mConnector.execute("volume", "mkdirs", appPath);
2993                return 0;
2994            } catch (NativeDaemonConnectorException e) {
2995                return e.getCode();
2996            }
2997        }
2998
2999        throw new SecurityException("Invalid mkdirs path: " + appFile);
3000    }
3001
3002    @Override
3003    public StorageVolume[] getVolumeList(int uid, String packageName, int flags) {
3004        final int userId = UserHandle.getUserId(uid);
3005
3006        final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0;
3007        final boolean realState = (flags & StorageManager.FLAG_REAL_STATE) != 0;
3008        final boolean includeInvisible = (flags & StorageManager.FLAG_INCLUDE_INVISIBLE) != 0;
3009
3010        final boolean userKeyUnlocked;
3011        final boolean storagePermission;
3012        final long token = Binder.clearCallingIdentity();
3013        try {
3014            userKeyUnlocked = isUserKeyUnlocked(userId);
3015            storagePermission = mMountServiceInternal.hasExternalStorage(uid, packageName);
3016        } finally {
3017            Binder.restoreCallingIdentity(token);
3018        }
3019
3020        boolean foundPrimary = false;
3021
3022        final ArrayList<StorageVolume> res = new ArrayList<>();
3023        synchronized (mLock) {
3024            for (int i = 0; i < mVolumes.size(); i++) {
3025                final VolumeInfo vol = mVolumes.valueAt(i);
3026                switch (vol.getType()) {
3027                    case VolumeInfo.TYPE_PUBLIC:
3028                    case VolumeInfo.TYPE_EMULATED:
3029                        break;
3030                    default:
3031                        continue;
3032                }
3033
3034                boolean match = false;
3035                if (forWrite) {
3036                    match = vol.isVisibleForWrite(userId);
3037                } else {
3038                    match = vol.isVisibleForRead(userId)
3039                            || (includeInvisible && vol.getPath() != null);
3040                }
3041                if (!match) continue;
3042
3043                boolean reportUnmounted = false;
3044                if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !userKeyUnlocked) {
3045                    reportUnmounted = true;
3046                } else if (!storagePermission && !realState) {
3047                    reportUnmounted = true;
3048                }
3049
3050                final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
3051                        reportUnmounted);
3052                if (vol.isPrimary()) {
3053                    res.add(0, userVol);
3054                    foundPrimary = true;
3055                } else {
3056                    res.add(userVol);
3057                }
3058            }
3059        }
3060
3061        if (!foundPrimary) {
3062            Log.w(TAG, "No primary storage defined yet; hacking together a stub");
3063
3064            final boolean primaryPhysical = SystemProperties.getBoolean(
3065                    StorageManager.PROP_PRIMARY_PHYSICAL, false);
3066
3067            final String id = "stub_primary";
3068            final File path = Environment.getLegacyExternalStorageDirectory();
3069            final String description = mContext.getString(android.R.string.unknownName);
3070            final boolean primary = true;
3071            final boolean removable = primaryPhysical;
3072            final boolean emulated = !primaryPhysical;
3073            final long mtpReserveSize = 0L;
3074            final boolean allowMassStorage = false;
3075            final long maxFileSize = 0L;
3076            final UserHandle owner = new UserHandle(userId);
3077            final String uuid = null;
3078            final String state = Environment.MEDIA_REMOVED;
3079
3080            res.add(0, new StorageVolume(id, StorageVolume.STORAGE_ID_INVALID, path,
3081                    description, primary, removable, emulated, mtpReserveSize,
3082                    allowMassStorage, maxFileSize, owner, uuid, state));
3083        }
3084
3085        return res.toArray(new StorageVolume[res.size()]);
3086    }
3087
3088    @Override
3089    public DiskInfo[] getDisks() {
3090        synchronized (mLock) {
3091            final DiskInfo[] res = new DiskInfo[mDisks.size()];
3092            for (int i = 0; i < mDisks.size(); i++) {
3093                res[i] = mDisks.valueAt(i);
3094            }
3095            return res;
3096        }
3097    }
3098
3099    @Override
3100    public VolumeInfo[] getVolumes(int flags) {
3101        synchronized (mLock) {
3102            final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
3103            for (int i = 0; i < mVolumes.size(); i++) {
3104                res[i] = mVolumes.valueAt(i);
3105            }
3106            return res;
3107        }
3108    }
3109
3110    @Override
3111    public VolumeRecord[] getVolumeRecords(int flags) {
3112        synchronized (mLock) {
3113            final VolumeRecord[] res = new VolumeRecord[mRecords.size()];
3114            for (int i = 0; i < mRecords.size(); i++) {
3115                res[i] = mRecords.valueAt(i);
3116            }
3117            return res;
3118        }
3119    }
3120
3121    private void addObbStateLocked(ObbState obbState) throws RemoteException {
3122        final IBinder binder = obbState.getBinder();
3123        List<ObbState> obbStates = mObbMounts.get(binder);
3124
3125        if (obbStates == null) {
3126            obbStates = new ArrayList<ObbState>();
3127            mObbMounts.put(binder, obbStates);
3128        } else {
3129            for (final ObbState o : obbStates) {
3130                if (o.rawPath.equals(obbState.rawPath)) {
3131                    throw new IllegalStateException("Attempt to add ObbState twice. "
3132                            + "This indicates an error in the MountService logic.");
3133                }
3134            }
3135        }
3136
3137        obbStates.add(obbState);
3138        try {
3139            obbState.link();
3140        } catch (RemoteException e) {
3141            /*
3142             * The binder died before we could link it, so clean up our state
3143             * and return failure.
3144             */
3145            obbStates.remove(obbState);
3146            if (obbStates.isEmpty()) {
3147                mObbMounts.remove(binder);
3148            }
3149
3150            // Rethrow the error so mountObb can get it
3151            throw e;
3152        }
3153
3154        mObbPathToStateMap.put(obbState.rawPath, obbState);
3155    }
3156
3157    private void removeObbStateLocked(ObbState obbState) {
3158        final IBinder binder = obbState.getBinder();
3159        final List<ObbState> obbStates = mObbMounts.get(binder);
3160        if (obbStates != null) {
3161            if (obbStates.remove(obbState)) {
3162                obbState.unlink();
3163            }
3164            if (obbStates.isEmpty()) {
3165                mObbMounts.remove(binder);
3166            }
3167        }
3168
3169        mObbPathToStateMap.remove(obbState.rawPath);
3170    }
3171
3172    private class ObbActionHandler extends Handler {
3173        private boolean mBound = false;
3174        private final List<ObbAction> mActions = new LinkedList<ObbAction>();
3175
3176        ObbActionHandler(Looper l) {
3177            super(l);
3178        }
3179
3180        @Override
3181        public void handleMessage(Message msg) {
3182            switch (msg.what) {
3183                case OBB_RUN_ACTION: {
3184                    final ObbAction action = (ObbAction) msg.obj;
3185
3186                    if (DEBUG_OBB)
3187                        Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
3188
3189                    // If a bind was already initiated we don't really
3190                    // need to do anything. The pending install
3191                    // will be processed later on.
3192                    if (!mBound) {
3193                        // If this is the only one pending we might
3194                        // have to bind to the service again.
3195                        if (!connectToService()) {
3196                            Slog.e(TAG, "Failed to bind to media container service");
3197                            action.handleError();
3198                            return;
3199                        }
3200                    }
3201
3202                    mActions.add(action);
3203                    break;
3204                }
3205                case OBB_MCS_BOUND: {
3206                    if (DEBUG_OBB)
3207                        Slog.i(TAG, "OBB_MCS_BOUND");
3208                    if (msg.obj != null) {
3209                        mContainerService = (IMediaContainerService) msg.obj;
3210                    }
3211                    if (mContainerService == null) {
3212                        // Something seriously wrong. Bail out
3213                        Slog.e(TAG, "Cannot bind to media container service");
3214                        for (ObbAction action : mActions) {
3215                            // Indicate service bind error
3216                            action.handleError();
3217                        }
3218                        mActions.clear();
3219                    } else if (mActions.size() > 0) {
3220                        final ObbAction action = mActions.get(0);
3221                        if (action != null) {
3222                            action.execute(this);
3223                        }
3224                    } else {
3225                        // Should never happen ideally.
3226                        Slog.w(TAG, "Empty queue");
3227                    }
3228                    break;
3229                }
3230                case OBB_MCS_RECONNECT: {
3231                    if (DEBUG_OBB)
3232                        Slog.i(TAG, "OBB_MCS_RECONNECT");
3233                    if (mActions.size() > 0) {
3234                        if (mBound) {
3235                            disconnectService();
3236                        }
3237                        if (!connectToService()) {
3238                            Slog.e(TAG, "Failed to bind to media container service");
3239                            for (ObbAction action : mActions) {
3240                                // Indicate service bind error
3241                                action.handleError();
3242                            }
3243                            mActions.clear();
3244                        }
3245                    }
3246                    break;
3247                }
3248                case OBB_MCS_UNBIND: {
3249                    if (DEBUG_OBB)
3250                        Slog.i(TAG, "OBB_MCS_UNBIND");
3251
3252                    // Delete pending install
3253                    if (mActions.size() > 0) {
3254                        mActions.remove(0);
3255                    }
3256                    if (mActions.size() == 0) {
3257                        if (mBound) {
3258                            disconnectService();
3259                        }
3260                    } else {
3261                        // There are more pending requests in queue.
3262                        // Just post MCS_BOUND message to trigger processing
3263                        // of next pending install.
3264                        mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
3265                    }
3266                    break;
3267                }
3268                case OBB_FLUSH_MOUNT_STATE: {
3269                    final String path = (String) msg.obj;
3270
3271                    if (DEBUG_OBB)
3272                        Slog.i(TAG, "Flushing all OBB state for path " + path);
3273
3274                    synchronized (mObbMounts) {
3275                        final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
3276
3277                        final Iterator<ObbState> i = mObbPathToStateMap.values().iterator();
3278                        while (i.hasNext()) {
3279                            final ObbState state = i.next();
3280
3281                            /*
3282                             * If this entry's source file is in the volume path
3283                             * that got unmounted, remove it because it's no
3284                             * longer valid.
3285                             */
3286                            if (state.canonicalPath.startsWith(path)) {
3287                                obbStatesToRemove.add(state);
3288                            }
3289                        }
3290
3291                        for (final ObbState obbState : obbStatesToRemove) {
3292                            if (DEBUG_OBB)
3293                                Slog.i(TAG, "Removing state for " + obbState.rawPath);
3294
3295                            removeObbStateLocked(obbState);
3296
3297                            try {
3298                                obbState.token.onObbResult(obbState.rawPath, obbState.nonce,
3299                                        OnObbStateChangeListener.UNMOUNTED);
3300                            } catch (RemoteException e) {
3301                                Slog.i(TAG, "Couldn't send unmount notification for  OBB: "
3302                                        + obbState.rawPath);
3303                            }
3304                        }
3305                    }
3306                    break;
3307                }
3308            }
3309        }
3310
3311        private boolean connectToService() {
3312            if (DEBUG_OBB)
3313                Slog.i(TAG, "Trying to bind to DefaultContainerService");
3314
3315            Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
3316            if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE,
3317                    UserHandle.SYSTEM)) {
3318                mBound = true;
3319                return true;
3320            }
3321            return false;
3322        }
3323
3324        private void disconnectService() {
3325            mContainerService = null;
3326            mBound = false;
3327            mContext.unbindService(mDefContainerConn);
3328        }
3329    }
3330
3331    abstract class ObbAction {
3332        private static final int MAX_RETRIES = 3;
3333        private int mRetries;
3334
3335        ObbState mObbState;
3336
3337        ObbAction(ObbState obbState) {
3338            mObbState = obbState;
3339        }
3340
3341        public void execute(ObbActionHandler handler) {
3342            try {
3343                if (DEBUG_OBB)
3344                    Slog.i(TAG, "Starting to execute action: " + toString());
3345                mRetries++;
3346                if (mRetries > MAX_RETRIES) {
3347                    Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
3348                    mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
3349                    handleError();
3350                } else {
3351                    handleExecute();
3352                    if (DEBUG_OBB)
3353                        Slog.i(TAG, "Posting install MCS_UNBIND");
3354                    mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
3355                }
3356            } catch (RemoteException e) {
3357                if (DEBUG_OBB)
3358                    Slog.i(TAG, "Posting install MCS_RECONNECT");
3359                mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
3360            } catch (Exception e) {
3361                if (DEBUG_OBB)
3362                    Slog.d(TAG, "Error handling OBB action", e);
3363                handleError();
3364                mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
3365            }
3366        }
3367
3368        abstract void handleExecute() throws RemoteException, IOException;
3369        abstract void handleError();
3370
3371        protected ObbInfo getObbInfo() throws IOException {
3372            ObbInfo obbInfo;
3373            try {
3374                obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath);
3375            } catch (RemoteException e) {
3376                Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
3377                        + mObbState.canonicalPath);
3378                obbInfo = null;
3379            }
3380            if (obbInfo == null) {
3381                throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath);
3382            }
3383            return obbInfo;
3384        }
3385
3386        protected void sendNewStatusOrIgnore(int status) {
3387            if (mObbState == null || mObbState.token == null) {
3388                return;
3389            }
3390
3391            try {
3392                mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
3393            } catch (RemoteException e) {
3394                Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
3395            }
3396        }
3397    }
3398
3399    class MountObbAction extends ObbAction {
3400        private final String mKey;
3401        private final int mCallingUid;
3402
3403        MountObbAction(ObbState obbState, String key, int callingUid) {
3404            super(obbState);
3405            mKey = key;
3406            mCallingUid = callingUid;
3407        }
3408
3409        @Override
3410        public void handleExecute() throws IOException, RemoteException {
3411            waitForReady();
3412            warnOnNotMounted();
3413
3414            final ObbInfo obbInfo = getObbInfo();
3415
3416            if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
3417                Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
3418                        + " which is owned by " + obbInfo.packageName);
3419                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3420                return;
3421            }
3422
3423            final boolean isMounted;
3424            synchronized (mObbMounts) {
3425                isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
3426            }
3427            if (isMounted) {
3428                Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
3429                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
3430                return;
3431            }
3432
3433            final String hashedKey;
3434            if (mKey == null) {
3435                hashedKey = "none";
3436            } else {
3437                try {
3438                    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
3439
3440                    KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
3441                            PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
3442                    SecretKey key = factory.generateSecret(ks);
3443                    BigInteger bi = new BigInteger(key.getEncoded());
3444                    hashedKey = bi.toString(16);
3445                } catch (NoSuchAlgorithmException e) {
3446                    Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
3447                    sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
3448                    return;
3449                } catch (InvalidKeySpecException e) {
3450                    Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
3451                    sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
3452                    return;
3453                }
3454            }
3455
3456            int rc = StorageResultCode.OperationSucceeded;
3457            try {
3458                mConnector.execute("obb", "mount", mObbState.canonicalPath, new SensitiveArg(hashedKey),
3459                        mObbState.ownerGid);
3460            } catch (NativeDaemonConnectorException e) {
3461                int code = e.getCode();
3462                if (code != VoldResponseCode.OpFailedStorageBusy) {
3463                    rc = StorageResultCode.OperationFailedInternalError;
3464                }
3465            }
3466
3467            if (rc == StorageResultCode.OperationSucceeded) {
3468                if (DEBUG_OBB)
3469                    Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
3470
3471                synchronized (mObbMounts) {
3472                    addObbStateLocked(mObbState);
3473                }
3474
3475                sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
3476            } else {
3477                Slog.e(TAG, "Couldn't mount OBB file: " + rc);
3478
3479                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
3480            }
3481        }
3482
3483        @Override
3484        public void handleError() {
3485            sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
3486        }
3487
3488        @Override
3489        public String toString() {
3490            StringBuilder sb = new StringBuilder();
3491            sb.append("MountObbAction{");
3492            sb.append(mObbState);
3493            sb.append('}');
3494            return sb.toString();
3495        }
3496    }
3497
3498    class UnmountObbAction extends ObbAction {
3499        private final boolean mForceUnmount;
3500
3501        UnmountObbAction(ObbState obbState, boolean force) {
3502            super(obbState);
3503            mForceUnmount = force;
3504        }
3505
3506        @Override
3507        public void handleExecute() throws IOException {
3508            waitForReady();
3509            warnOnNotMounted();
3510
3511            final ObbState existingState;
3512            synchronized (mObbMounts) {
3513                existingState = mObbPathToStateMap.get(mObbState.rawPath);
3514            }
3515
3516            if (existingState == null) {
3517                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
3518                return;
3519            }
3520
3521            if (existingState.ownerGid != mObbState.ownerGid) {
3522                Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
3523                        + " (owned by GID " + existingState.ownerGid + ")");
3524                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3525                return;
3526            }
3527
3528            int rc = StorageResultCode.OperationSucceeded;
3529            try {
3530                final Command cmd = new Command("obb", "unmount", mObbState.canonicalPath);
3531                if (mForceUnmount) {
3532                    cmd.appendArg("force");
3533                }
3534                mConnector.execute(cmd);
3535            } catch (NativeDaemonConnectorException e) {
3536                int code = e.getCode();
3537                if (code == VoldResponseCode.OpFailedStorageBusy) {
3538                    rc = StorageResultCode.OperationFailedStorageBusy;
3539                } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
3540                    // If it's not mounted then we've already won.
3541                    rc = StorageResultCode.OperationSucceeded;
3542                } else {
3543                    rc = StorageResultCode.OperationFailedInternalError;
3544                }
3545            }
3546
3547            if (rc == StorageResultCode.OperationSucceeded) {
3548                synchronized (mObbMounts) {
3549                    removeObbStateLocked(existingState);
3550                }
3551
3552                sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
3553            } else {
3554                Slog.w(TAG, "Could not unmount OBB: " + existingState);
3555                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
3556            }
3557        }
3558
3559        @Override
3560        public void handleError() {
3561            sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
3562        }
3563
3564        @Override
3565        public String toString() {
3566            StringBuilder sb = new StringBuilder();
3567            sb.append("UnmountObbAction{");
3568            sb.append(mObbState);
3569            sb.append(",force=");
3570            sb.append(mForceUnmount);
3571            sb.append('}');
3572            return sb.toString();
3573        }
3574    }
3575
3576    private static class Callbacks extends Handler {
3577        private static final int MSG_STORAGE_STATE_CHANGED = 1;
3578        private static final int MSG_VOLUME_STATE_CHANGED = 2;
3579        private static final int MSG_VOLUME_RECORD_CHANGED = 3;
3580        private static final int MSG_VOLUME_FORGOTTEN = 4;
3581        private static final int MSG_DISK_SCANNED = 5;
3582        private static final int MSG_DISK_DESTROYED = 6;
3583
3584        private final RemoteCallbackList<IMountServiceListener>
3585                mCallbacks = new RemoteCallbackList<>();
3586
3587        public Callbacks(Looper looper) {
3588            super(looper);
3589        }
3590
3591        public void register(IMountServiceListener callback) {
3592            mCallbacks.register(callback);
3593        }
3594
3595        public void unregister(IMountServiceListener callback) {
3596            mCallbacks.unregister(callback);
3597        }
3598
3599        @Override
3600        public void handleMessage(Message msg) {
3601            final SomeArgs args = (SomeArgs) msg.obj;
3602            final int n = mCallbacks.beginBroadcast();
3603            for (int i = 0; i < n; i++) {
3604                final IMountServiceListener callback = mCallbacks.getBroadcastItem(i);
3605                try {
3606                    invokeCallback(callback, msg.what, args);
3607                } catch (RemoteException ignored) {
3608                }
3609            }
3610            mCallbacks.finishBroadcast();
3611            args.recycle();
3612        }
3613
3614        private void invokeCallback(IMountServiceListener callback, int what, SomeArgs args)
3615                throws RemoteException {
3616            switch (what) {
3617                case MSG_STORAGE_STATE_CHANGED: {
3618                    callback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
3619                            (String) args.arg3);
3620                    break;
3621                }
3622                case MSG_VOLUME_STATE_CHANGED: {
3623                    callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
3624                    break;
3625                }
3626                case MSG_VOLUME_RECORD_CHANGED: {
3627                    callback.onVolumeRecordChanged((VolumeRecord) args.arg1);
3628                    break;
3629                }
3630                case MSG_VOLUME_FORGOTTEN: {
3631                    callback.onVolumeForgotten((String) args.arg1);
3632                    break;
3633                }
3634                case MSG_DISK_SCANNED: {
3635                    callback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
3636                    break;
3637                }
3638                case MSG_DISK_DESTROYED: {
3639                    callback.onDiskDestroyed((DiskInfo) args.arg1);
3640                    break;
3641                }
3642            }
3643        }
3644
3645        private void notifyStorageStateChanged(String path, String oldState, String newState) {
3646            final SomeArgs args = SomeArgs.obtain();
3647            args.arg1 = path;
3648            args.arg2 = oldState;
3649            args.arg3 = newState;
3650            obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
3651        }
3652
3653        private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
3654            final SomeArgs args = SomeArgs.obtain();
3655            args.arg1 = vol.clone();
3656            args.argi2 = oldState;
3657            args.argi3 = newState;
3658            obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
3659        }
3660
3661        private void notifyVolumeRecordChanged(VolumeRecord rec) {
3662            final SomeArgs args = SomeArgs.obtain();
3663            args.arg1 = rec.clone();
3664            obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
3665        }
3666
3667        private void notifyVolumeForgotten(String fsUuid) {
3668            final SomeArgs args = SomeArgs.obtain();
3669            args.arg1 = fsUuid;
3670            obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
3671        }
3672
3673        private void notifyDiskScanned(DiskInfo disk, int volumeCount) {
3674            final SomeArgs args = SomeArgs.obtain();
3675            args.arg1 = disk.clone();
3676            args.argi2 = volumeCount;
3677            obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
3678        }
3679
3680        private void notifyDiskDestroyed(DiskInfo disk) {
3681            final SomeArgs args = SomeArgs.obtain();
3682            args.arg1 = disk.clone();
3683            obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
3684        }
3685    }
3686
3687    @Override
3688    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
3689        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
3690
3691        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ", 160);
3692        synchronized (mLock) {
3693            pw.println("Disks:");
3694            pw.increaseIndent();
3695            for (int i = 0; i < mDisks.size(); i++) {
3696                final DiskInfo disk = mDisks.valueAt(i);
3697                disk.dump(pw);
3698            }
3699            pw.decreaseIndent();
3700
3701            pw.println();
3702            pw.println("Volumes:");
3703            pw.increaseIndent();
3704            for (int i = 0; i < mVolumes.size(); i++) {
3705                final VolumeInfo vol = mVolumes.valueAt(i);
3706                if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue;
3707                vol.dump(pw);
3708            }
3709            pw.decreaseIndent();
3710
3711            pw.println();
3712            pw.println("Records:");
3713            pw.increaseIndent();
3714            for (int i = 0; i < mRecords.size(); i++) {
3715                final VolumeRecord note = mRecords.valueAt(i);
3716                note.dump(pw);
3717            }
3718            pw.decreaseIndent();
3719
3720            pw.println();
3721            pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
3722            pw.println("Force adoptable: " + mForceAdoptable);
3723            pw.println();
3724            pw.println("Local unlocked users: " + Arrays.toString(mLocalUnlockedUsers));
3725            pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
3726        }
3727
3728        synchronized (mObbMounts) {
3729            pw.println();
3730            pw.println("mObbMounts:");
3731            pw.increaseIndent();
3732            final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet()
3733                    .iterator();
3734            while (binders.hasNext()) {
3735                Entry<IBinder, List<ObbState>> e = binders.next();
3736                pw.println(e.getKey() + ":");
3737                pw.increaseIndent();
3738                final List<ObbState> obbStates = e.getValue();
3739                for (final ObbState obbState : obbStates) {
3740                    pw.println(obbState);
3741                }
3742                pw.decreaseIndent();
3743            }
3744            pw.decreaseIndent();
3745
3746            pw.println();
3747            pw.println("mObbPathToStateMap:");
3748            pw.increaseIndent();
3749            final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
3750            while (maps.hasNext()) {
3751                final Entry<String, ObbState> e = maps.next();
3752                pw.print(e.getKey());
3753                pw.print(" -> ");
3754                pw.println(e.getValue());
3755            }
3756            pw.decreaseIndent();
3757        }
3758
3759        pw.println();
3760        pw.println("mConnector:");
3761        pw.increaseIndent();
3762        mConnector.dump(fd, pw, args);
3763        pw.decreaseIndent();
3764
3765        pw.println();
3766        pw.println("mCryptConnector:");
3767        pw.increaseIndent();
3768        mCryptConnector.dump(fd, pw, args);
3769        pw.decreaseIndent();
3770
3771        pw.println();
3772        pw.print("Last maintenance: ");
3773        pw.println(TimeUtils.formatForLogging(mLastMaintenance));
3774    }
3775
3776    /** {@inheritDoc} */
3777    @Override
3778    public void monitor() {
3779        if (mConnector != null) {
3780            mConnector.monitor();
3781        }
3782        if (mCryptConnector != null) {
3783            mCryptConnector.monitor();
3784        }
3785    }
3786
3787    private final class MountServiceInternalImpl extends MountServiceInternal {
3788        // Not guarded by a lock.
3789        private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
3790                new CopyOnWriteArrayList<>();
3791
3792        @Override
3793        public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
3794            // No locking - CopyOnWriteArrayList
3795            mPolicies.add(policy);
3796        }
3797
3798        @Override
3799        public void onExternalStoragePolicyChanged(int uid, String packageName) {
3800            final int mountMode = getExternalStorageMountMode(uid, packageName);
3801            remountUidExternalStorage(uid, mountMode);
3802        }
3803
3804        @Override
3805        public int getExternalStorageMountMode(int uid, String packageName) {
3806            // No locking - CopyOnWriteArrayList
3807            int mountMode = Integer.MAX_VALUE;
3808            for (ExternalStorageMountPolicy policy : mPolicies) {
3809                final int policyMode = policy.getMountMode(uid, packageName);
3810                if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
3811                    return Zygote.MOUNT_EXTERNAL_NONE;
3812                }
3813                mountMode = Math.min(mountMode, policyMode);
3814            }
3815            if (mountMode == Integer.MAX_VALUE) {
3816                return Zygote.MOUNT_EXTERNAL_NONE;
3817            }
3818            return mountMode;
3819        }
3820
3821        public boolean hasExternalStorage(int uid, String packageName) {
3822            // No need to check for system uid. This avoids a deadlock between
3823            // PackageManagerService and AppOpsService.
3824            if (uid == Process.SYSTEM_UID) {
3825                return true;
3826            }
3827            // No locking - CopyOnWriteArrayList
3828            for (ExternalStorageMountPolicy policy : mPolicies) {
3829                final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
3830                if (!policyHasStorage) {
3831                    return false;
3832                }
3833            }
3834            return true;
3835        }
3836    }
3837}
3838