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