blob: 822fc90cd78e7cfff34e03569fd882687b181c3b [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -080019import static android.Manifest.permission.INSTALL_PACKAGES;
Jeff Sharkey6fd69942019-03-26 17:53:35 -060020import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
21import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -080022import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
23import static android.app.AppOpsManager.MODE_ALLOWED;
Jeff Sharkey11697f52018-12-13 10:14:42 -070024import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
Jeff Sharkey6fd69942019-03-26 17:53:35 -060025import static android.app.AppOpsManager.OP_READ_EXTERNAL_STORAGE;
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -080026import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES;
Jeff Sharkey6fd69942019-03-26 17:53:35 -060027import static android.app.AppOpsManager.OP_WRITE_EXTERNAL_STORAGE;
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -080028import static android.content.pm.PackageManager.PERMISSION_GRANTED;
Jeff Sharkey39466322018-12-05 19:19:52 -070029import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
Jeff Sharkey0095a822018-02-15 13:06:53 -070030import static android.os.storage.OnObbStateChangeListener.ERROR_ALREADY_MOUNTED;
31import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT;
32import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT;
33import static android.os.storage.OnObbStateChangeListener.ERROR_INTERNAL;
34import static android.os.storage.OnObbStateChangeListener.ERROR_NOT_MOUNTED;
35import static android.os.storage.OnObbStateChangeListener.ERROR_PERMISSION_DENIED;
36import static android.os.storage.OnObbStateChangeListener.MOUNTED;
37import static android.os.storage.OnObbStateChangeListener.UNMOUNTED;
Jeff Sharkey5790af02018-08-13 17:42:54 -060038
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070039import static com.android.internal.util.XmlUtils.readIntAttribute;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070040import static com.android.internal.util.XmlUtils.readLongAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070041import static com.android.internal.util.XmlUtils.readStringAttribute;
42import static com.android.internal.util.XmlUtils.writeIntAttribute;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070043import static com.android.internal.util.XmlUtils.writeLongAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070044import static com.android.internal.util.XmlUtils.writeStringAttribute;
Jeff Sharkey5790af02018-08-13 17:42:54 -060045
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070046import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
47import static org.xmlpull.v1.XmlPullParser.START_TAG;
48
Jason parks8888c592011-01-20 22:46:41 -060049import android.Manifest;
Jeff Sharkeyef10ee02015-07-05 14:17:27 -070050import android.annotation.Nullable;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -070051import android.app.ActivityManager;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -070052import android.app.AppOpsManager;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070053import android.app.IActivityManager;
Jeff Sharkey9765e442017-12-14 22:15:14 -070054import android.app.KeyguardManager;
Pavel Grafovce72ef02018-01-10 17:14:11 +000055import android.app.admin.SecurityLog;
Jeff Sharkey9bed0702017-01-23 20:37:05 -070056import android.app.usage.StorageStatsManager;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070057import android.content.BroadcastReceiver;
Jeff Sharkeyb0c363b22018-12-15 11:53:03 -070058import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.content.Context;
60import android.content.Intent;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070061import android.content.IntentFilter;
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -080062import android.content.pm.IPackageManager;
Jeff Sharkey275e3e42015-04-24 16:10:32 -070063import android.content.pm.IPackageMoveObserver;
64import android.content.pm.PackageManager;
Sudheer Shanka0a541a52018-07-31 13:21:11 -070065import android.content.pm.PackageManagerInternal;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070066import android.content.pm.ProviderInfo;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070067import android.content.pm.UserInfo;
Elliott Hughesf839b4f2014-09-26 12:30:47 -070068import android.content.res.Configuration;
Kenny Root02c87302010-07-01 08:10:18 -070069import android.content.res.ObbInfo;
Daniel Colascione766b6322018-01-08 19:10:36 -080070import android.database.ContentObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071import android.net.Uri;
Kenny Root02c87302010-07-01 08:10:18 -070072import android.os.Binder;
Jeff Sharkey4c099d02015-05-15 13:45:00 -070073import android.os.DropBoxManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070074import android.os.Environment;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070075import android.os.Environment.UserEnvironment;
Jeff Sharkey48877892015-03-18 11:27:19 -070076import android.os.FileUtils;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080077import android.os.Handler;
Dianne Hackbornefa92b22013-05-03 14:11:43 -070078import android.os.HandlerThread;
Kenny Roota02b8b02010-08-05 16:14:17 -070079import android.os.IBinder;
Jin Qian12690d52017-10-13 18:17:04 -070080import android.os.IStoraged;
Jeff Sharkey1019de92017-09-06 13:47:03 -060081import android.os.IVold;
Jeff Sharkey8058fe62017-09-13 11:50:33 -060082import android.os.IVoldListener;
Zim95eca1d2019-11-15 18:03:00 +000083import android.os.IVoldMountCallback;
Jeff Sharkeyb302c542017-09-15 12:57:59 -060084import android.os.IVoldTaskListener;
Daniel Sandler5f27ef42010-03-16 15:42:02 -040085import android.os.Looper;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080086import android.os.Message;
Daichi Hirono9e8d9e22015-11-13 14:37:00 +090087import android.os.ParcelFileDescriptor;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -070088import android.os.ParcelableException;
Jeff Sharkeyb302c542017-09-15 12:57:59 -060089import android.os.PersistableBundle;
Jeff Sharkeyce14cd02015-12-07 15:35:42 -070090import android.os.PowerManager;
Jeff Sharkey9527b222015-06-24 15:24:48 -070091import android.os.Process;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070092import android.os.RemoteCallbackList;
San Mehat4270e1e2010-01-29 05:32:19 -080093import android.os.RemoteException;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -080094import android.os.ServiceManager;
Paul Crowleyfc0b5192018-07-02 13:58:10 -070095import android.os.ServiceSpecificException;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -070096import android.os.SystemClock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070098import android.os.UserHandle;
Emily Bernier92aa5a22014-07-07 10:11:48 -040099import android.os.UserManager;
Sudheer Shankab1613982019-05-16 16:55:50 -0700100import android.os.UserManagerInternal;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700101import android.os.storage.DiskInfo;
Kenny Roota02b8b02010-08-05 16:14:17 -0700102import android.os.storage.IObbActionListener;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700103import android.os.storage.IStorageEventListener;
Sudheer Shanka2250d562016-11-07 15:41:02 -0800104import android.os.storage.IStorageManager;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700105import android.os.storage.IStorageShutdownObserver;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700106import android.os.storage.OnObbStateChangeListener;
Paul Lawrence46791e72014-04-03 09:10:26 -0700107import android.os.storage.StorageManager;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700108import android.os.storage.StorageManagerInternal;
Mike Lockwood2f6a3882011-05-09 19:08:06 -0700109import android.os.storage.StorageVolume;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700110import android.os.storage.VolumeInfo;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700111import android.os.storage.VolumeRecord;
Jeff Sharkey5d0c55c2019-01-24 14:32:31 -0700112import android.provider.DeviceConfig;
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700113import android.provider.MediaStore;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700114import android.provider.Settings;
Inseob Kimc1246e62018-11-08 13:13:54 +0900115import android.sysprop.VoldProperties;
Jason parksf7b3cd42011-01-27 09:28:25 -0600116import android.text.TextUtils;
Jeff Sharkey1783f142015-04-17 10:52:51 -0700117import android.text.format.DateUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -0700118import android.util.ArrayMap;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700119import android.util.AtomicFile;
Jeff Sharkey9f2dc052018-01-07 16:47:31 -0700120import android.util.DataUnit;
Abhijeet Kaurb9847712019-11-19 16:35:47 +0000121import android.util.FeatureFlagUtils;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700122import android.util.Log;
Felipe Leme281389a2016-10-10 17:12:20 -0700123import android.util.Pair;
San Mehata5078592010-03-25 09:36:54 -0700124import android.util.Slog;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700125import android.util.TimeUtils;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700126import android.util.Xml;
Jeff Sharkey48877892015-03-18 11:27:19 -0700127
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -0800128import com.android.internal.annotations.GuardedBy;
Sudheer Shankaff971bc2018-12-13 17:39:59 -0800129import com.android.internal.app.IAppOpsCallback;
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -0800130import com.android.internal.app.IAppOpsService;
Daichi Hirono9fb00182016-11-08 14:12:17 +0900131import com.android.internal.os.AppFuseMount;
Jeff Sharkey1019de92017-09-06 13:47:03 -0600132import com.android.internal.os.BackgroundThread;
Daichi Hirono812c95d2017-02-08 16:20:20 +0900133import com.android.internal.os.FuseUnavailableMountException;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700134import com.android.internal.os.SomeArgs;
Jeff Sharkey9527b222015-06-24 15:24:48 -0700135import com.android.internal.os.Zygote;
Jeff Sharkey48877892015-03-18 11:27:19 -0700136import com.android.internal.util.ArrayUtils;
Jeff Sharkey11697f52018-12-13 10:14:42 -0700137import com.android.internal.util.CollectionUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600138import com.android.internal.util.DumpUtils;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700139import com.android.internal.util.FastXmlSerializer;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800140import com.android.internal.util.HexDump;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -0700141import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700142import com.android.internal.util.Preconditions;
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700143import com.android.internal.widget.LockPatternUtils;
Daichi Hirono9fb00182016-11-08 14:12:17 +0900144import com.android.server.storage.AppFuseBridge;
Zim42f1e9f2019-08-15 17:35:00 +0100145import com.android.server.storage.StorageSessionController;
Zim17be6f92019-09-25 14:37:55 +0100146import com.android.server.storage.StorageSessionController.ExternalStorageServiceException;
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700147import com.android.server.wm.ActivityTaskManagerInternal;
148import com.android.server.wm.ActivityTaskManagerInternal.ScreenObserver;
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700149
Jeff Sharkey5790af02018-08-13 17:42:54 -0600150import libcore.io.IoUtils;
151import libcore.util.EmptyArray;
152
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700153import org.xmlpull.v1.XmlPullParser;
154import org.xmlpull.v1.XmlPullParserException;
155import org.xmlpull.v1.XmlSerializer;
156
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700157import java.io.File;
Kenny Root38cf8862010-09-26 14:18:51 -0700158import java.io.FileDescriptor;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700159import java.io.FileInputStream;
160import java.io.FileNotFoundException;
Christopher Tate7265abe2014-11-21 13:54:45 -0800161import java.io.FileOutputStream;
Kenny Root05105f72010-09-22 17:29:43 -0700162import java.io.IOException;
Kenny Root38cf8862010-09-26 14:18:51 -0700163import java.io.PrintWriter;
Kenny Root3b1abba2010-10-13 15:00:07 -0700164import java.math.BigInteger;
Paul Lawrence8e397362014-01-27 15:22:30 -0800165import java.nio.charset.StandardCharsets;
Jeff Sharkey0095a822018-02-15 13:06:53 -0700166import java.security.GeneralSecurityException;
Kenny Root3b1abba2010-10-13 15:00:07 -0700167import java.security.spec.KeySpec;
San Mehat22dd86e2010-01-12 12:21:18 -0800168import java.util.ArrayList;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800169import java.util.Arrays;
Kenny Roota02b8b02010-08-05 16:14:17 -0700170import java.util.HashMap;
Kenny Root38cf8862010-09-26 14:18:51 -0700171import java.util.Iterator;
Kenny Roota02b8b02010-08-05 16:14:17 -0700172import java.util.LinkedList;
173import java.util.List;
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700174import java.util.Locale;
Kenny Roota02b8b02010-08-05 16:14:17 -0700175import java.util.Map;
Kenny Root38cf8862010-09-26 14:18:51 -0700176import java.util.Map.Entry;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700177import java.util.Objects;
Svet Ganov6ee871e2015-07-10 14:29:33 -0700178import java.util.concurrent.CopyOnWriteArrayList;
Kenny Root51a573c2012-05-17 13:30:28 -0700179import java.util.concurrent.CountDownLatch;
180import java.util.concurrent.TimeUnit;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700181import java.util.concurrent.TimeoutException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182
Kenny Root3b1abba2010-10-13 15:00:07 -0700183import javax.crypto.SecretKey;
184import javax.crypto.SecretKeyFactory;
185import javax.crypto.spec.PBEKeySpec;
186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187/**
Jeff Sharkey48877892015-03-18 11:27:19 -0700188 * Service responsible for various storage media. Connects to {@code vold} to
189 * watch for and manage dynamically added storage, such as SD cards and USB mass
190 * storage. Also decides how storage should be presented to users on the device.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 */
Jeff Sharkey9765e442017-12-14 22:15:14 -0700192class StorageManagerService extends IStorageManager.Stub
193 implements Watchdog.Monitor, ScreenObserver {
Jason parks5af0b912010-11-29 09:05:25 -0600194
Christopher Tated417d622013-08-19 16:14:25 -0700195 // Static direct instance pointer for the tightly-coupled idle service to use
Sudheer Shanka2250d562016-11-07 15:41:02 -0800196 static StorageManagerService sSelf = null;
Christopher Tated417d622013-08-19 16:14:25 -0700197
Daniel Colascione766b6322018-01-08 19:10:36 -0800198 /* Read during boot to decide whether to enable zram when available */
199 private static final String ZRAM_ENABLED_PROPERTY =
Sudheer Shanka0a541a52018-07-31 13:21:11 -0700200 "persist.sys.zram_enabled";
201
Jeff Sharkey10ec9d82018-11-28 14:52:45 -0700202 private static final boolean ENABLE_ISOLATED_STORAGE = StorageManager.hasIsolatedStorage();
Sudheer Shanka0a541a52018-07-31 13:21:11 -0700203
Matt Pape19ea8a62019-03-18 10:38:25 -0700204 /**
205 * If {@code 1}, enables the isolated storage feature. If {@code -1},
206 * disables the isolated storage feature. If {@code 0}, uses the default
207 * value from the build system.
208 */
209 private static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
210
shafikb2992b62019-10-01 15:31:02 +0100211 /**
212 * If {@code 1}, enables FuseDaemon to intercept file system ops. If {@code -1},
213 * disables FuseDaemon. If {@code 0}, uses the default value from the build system.
214 */
215 private static final String FUSE_ENABLED = "fuse_enabled";
216
Jeff Sharkey56e62932015-03-21 20:41:00 -0700217 public static class Lifecycle extends SystemService {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800218 private StorageManagerService mStorageManagerService;
Jeff Sharkey56e62932015-03-21 20:41:00 -0700219
220 public Lifecycle(Context context) {
221 super(context);
222 }
223
224 @Override
225 public void onStart() {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800226 mStorageManagerService = new StorageManagerService(getContext());
227 publishBinderService("mount", mStorageManagerService);
228 mStorageManagerService.start();
Jeff Sharkey56e62932015-03-21 20:41:00 -0700229 }
230
231 @Override
232 public void onBootPhase(int phase) {
Jeff Sharkey11697f52018-12-13 10:14:42 -0700233 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
234 mStorageManagerService.servicesReady();
235 } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800236 mStorageManagerService.systemReady();
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900237 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800238 mStorageManagerService.bootCompleted();
Jeff Sharkey56e62932015-03-21 20:41:00 -0700239 }
240 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700241
242 @Override
Jeff Sharkeyab15c392016-05-05 11:45:01 -0600243 public void onSwitchUser(int userHandle) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800244 mStorageManagerService.mCurrentUserId = userHandle;
Jeff Sharkeyab15c392016-05-05 11:45:01 -0600245 }
246
247 @Override
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700248 public void onUnlockUser(int userHandle) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800249 mStorageManagerService.onUnlockUser(userHandle);
Jeff Sharkey48877892015-03-18 11:27:19 -0700250 }
251
252 @Override
253 public void onCleanupUser(int userHandle) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800254 mStorageManagerService.onCleanupUser(userHandle);
Jeff Sharkey48877892015-03-18 11:27:19 -0700255 }
Jeff Sharkey56e62932015-03-21 20:41:00 -0700256 }
257
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800258 private static final boolean DEBUG_EVENTS = false;
Kenny Rootb7db2722011-01-25 16:39:35 -0800259 private static final boolean DEBUG_OBB = false;
Kenny Root02c87302010-07-01 08:10:18 -0700260
Jeff Sharkeyc3c72872018-06-06 15:35:53 -0600261 /**
262 * We now talk to vold over Binder, and it has its own internal lock to
263 * serialize certain calls. All long-running operations have been migrated
264 * to be async with callbacks, so we want watchdog to fire if vold wedges.
265 */
266 private static final boolean WATCHDOG_ENABLE = true;
Kenny Root07714d42011-08-17 17:49:28 -0700267
Jeff Sharkey00455bf2016-11-04 14:45:24 -0600268 /**
269 * Our goal is for all Android devices to be usable as development devices,
270 * which includes the new Direct Boot mode added in N. For devices that
271 * don't have native FBE support, we offer an emulation mode for developer
272 * testing purposes, but if it's prohibitively difficult to support this
273 * mode, it can be disabled for specific products using this flag.
274 */
275 private static final boolean EMULATE_FBE_SUPPORTED = true;
276
Sudheer Shanka2250d562016-11-07 15:41:02 -0800277 private static final String TAG = "StorageManagerService";
Jeff Sharkey6fd69942019-03-26 17:53:35 -0600278 private static final boolean LOCAL_LOGV = Log.isLoggable(TAG, Log.VERBOSE);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700279
Jeff Sharkey9756d752015-05-14 21:07:42 -0700280 private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700281 private static final String TAG_STORAGE_TRIM = "storage_trim";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700283 /** Magic value sent by MoveTask.cpp */
284 private static final int MOVE_STATUS_COPY_FINISHED = 82;
285
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700286 private static final int VERSION_INIT = 1;
287 private static final int VERSION_ADD_PRIMARY = 2;
Jeff Sharkeyfced5342015-05-10 14:53:34 -0700288 private static final int VERSION_FIX_PRIMARY = 3;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700289
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700290 private static final String TAG_VOLUMES = "volumes";
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700291 private static final String ATTR_VERSION = "version";
292 private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700293 private static final String TAG_VOLUME = "volume";
294 private static final String ATTR_TYPE = "type";
295 private static final String ATTR_FS_UUID = "fsUuid";
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700296 private static final String ATTR_PART_GUID = "partGuid";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700297 private static final String ATTR_NICKNAME = "nickname";
298 private static final String ATTR_USER_FLAGS = "userFlags";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700299 private static final String ATTR_CREATED_MILLIS = "createdMillis";
Jeff Sharkey3811f352019-05-14 11:54:36 -0600300 private static final String ATTR_LAST_SEEN_MILLIS = "lastSeenMillis";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700301 private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis";
302 private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700303
Philip P. Moltmannc94ba822019-03-04 16:48:22 -0800304 private static final String[] ALL_STORAGE_PERMISSIONS = {
305 Manifest.permission.READ_EXTERNAL_STORAGE,
Philip P. Moltmann129a0b02019-03-27 12:24:45 -0700306 Manifest.permission.WRITE_EXTERNAL_STORAGE
Philip P. Moltmannc94ba822019-03-04 16:48:22 -0800307 };
308
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700309 private final AtomicFile mSettingsFile;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700310
Jeff Sharkey48877892015-03-18 11:27:19 -0700311 /**
312 * <em>Never</em> hold the lock while performing downcalls into vold, since
313 * unsolicited events can suddenly appear to update data structures.
314 */
Jeff Sharkey5f3e9342017-03-13 14:53:11 -0600315 private final Object mLock = LockGuard.installNewLock(LockGuard.INDEX_STORAGE);
Jeff Sharkey48877892015-03-18 11:27:19 -0700316
Sudheer Shanka0a541a52018-07-31 13:21:11 -0700317 /**
318 * Similar to {@link #mLock}, never hold this lock while performing downcalls into vold.
319 * Also, never hold this while calling into PackageManagerService since it is used in callbacks
320 * from PackageManagerService.
321 *
322 * If both {@link #mLock} and this lock need to be held, {@link #mLock} should be acquired
323 * before this.
324 *
325 * Use -PL suffix for methods that need to called with this lock held.
326 */
327 private final Object mPackagesLock = new Object();
328
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700329 /** Set of users that we know are unlocked. */
Jeff Sharkey48877892015-03-18 11:27:19 -0700330 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700331 private int[] mLocalUnlockedUsers = EmptyArray.INT;
332 /** Set of users that system knows are unlocked. */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800333 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700334 private int[] mSystemUnlockedUsers = EmptyArray.INT;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700335
336 /** Map from disk ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700337 @GuardedBy("mLock")
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700338 private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700339 /** Map from volume ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700340 @GuardedBy("mLock")
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700341 private final ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
Jeff Sharkey48877892015-03-18 11:27:19 -0700342
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700343 /** Map from UUID to record */
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700344 @GuardedBy("mLock")
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700345 private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>();
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700346 @GuardedBy("mLock")
347 private String mPrimaryStorageUuid;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700348
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700349 /** Map from disk ID to latches */
350 @GuardedBy("mLock")
351 private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
352
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700353 @GuardedBy("mLock")
354 private IPackageMoveObserver mMoveCallback;
355 @GuardedBy("mLock")
356 private String mMoveTargetUuid;
357
Martijn Coenen44db1ac2019-12-03 16:06:19 +0100358 private volatile int mMediaStoreAuthorityAppId = -1;
Zim74a9bba2019-09-03 20:49:13 +0100359
Jeff Sharkeyab15c392016-05-05 11:45:01 -0600360 private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
361
Daichi Hirono9fb00182016-11-08 14:12:17 +0900362 /** Holding lock for AppFuse business */
363 private final Object mAppFuseLock = new Object();
364
365 @GuardedBy("mAppFuseLock")
366 private int mNextAppFuseName = 0;
367
368 @GuardedBy("mAppFuseLock")
Daichi Hironoe56740d2017-02-02 13:56:45 +0900369 private AppFuseBridge mAppFuseBridge = null;
Daichi Hirono9fb00182016-11-08 14:12:17 +0900370
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700371 private VolumeInfo findVolumeByIdOrThrow(String id) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700372 synchronized (mLock) {
373 final VolumeInfo vol = mVolumes.get(id);
374 if (vol != null) {
375 return vol;
376 }
377 }
378 throw new IllegalArgumentException("No volume found for ID " + id);
379 }
380
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700381 private String findVolumeIdForPathOrThrow(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700382 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700383 for (int i = 0; i < mVolumes.size(); i++) {
384 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700385 if (vol.path != null && path.startsWith(vol.path)) {
386 return vol.id;
Jeff Sharkey48877892015-03-18 11:27:19 -0700387 }
388 }
389 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700390 throw new IllegalArgumentException("No volume found for path " + path);
Jeff Sharkey48877892015-03-18 11:27:19 -0700391 }
392
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700393 private VolumeRecord findRecordForPath(String path) {
394 synchronized (mLock) {
395 for (int i = 0; i < mVolumes.size(); i++) {
396 final VolumeInfo vol = mVolumes.valueAt(i);
397 if (vol.path != null && path.startsWith(vol.path)) {
398 return mRecords.get(vol.fsUuid);
399 }
400 }
401 }
402 return null;
403 }
404
405 private String scrubPath(String path) {
406 if (path.startsWith(Environment.getDataDirectory().getAbsolutePath())) {
407 return "internal";
408 }
409 final VolumeRecord rec = findRecordForPath(path);
410 if (rec == null || rec.createdMillis == 0) {
411 return "unknown";
412 } else {
413 return "ext:" + (int) ((System.currentTimeMillis() - rec.createdMillis)
414 / DateUtils.WEEK_IN_MILLIS) + "w";
415 }
416 }
417
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700418 private @Nullable VolumeInfo findStorageForUuid(String volumeUuid) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700419 final StorageManager storage = mContext.getSystemService(StorageManager.class);
420 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
Zim17be6f92019-09-25 14:37:55 +0100421 return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL + ";" + 0);
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700422 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
423 return storage.getPrimaryPhysicalVolume();
424 } else {
425 return storage.findEmulatedForPrivate(storage.findVolumeByUuid(volumeUuid));
426 }
427 }
428
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700429 private boolean shouldBenchmark() {
430 final long benchInterval = Settings.Global.getLong(mContext.getContentResolver(),
431 Settings.Global.STORAGE_BENCHMARK_INTERVAL, DateUtils.WEEK_IN_MILLIS);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700432 if (benchInterval == -1) {
433 return false;
434 } else if (benchInterval == 0) {
435 return true;
436 }
437
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700438 synchronized (mLock) {
439 for (int i = 0; i < mVolumes.size(); i++) {
440 final VolumeInfo vol = mVolumes.valueAt(i);
441 final VolumeRecord rec = mRecords.get(vol.fsUuid);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700442 if (vol.isMountedWritable() && rec != null) {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700443 final long benchAge = System.currentTimeMillis() - rec.lastBenchMillis;
444 if (benchAge >= benchInterval) {
445 return true;
446 }
447 }
448 }
449 return false;
450 }
451 }
452
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700453 private CountDownLatch findOrCreateDiskScanLatch(String diskId) {
454 synchronized (mLock) {
455 CountDownLatch latch = mDiskScanLatches.get(diskId);
456 if (latch == null) {
457 latch = new CountDownLatch(1);
458 mDiskScanLatches.put(diskId, latch);
459 }
460 return latch;
461 }
462 }
463
Paul Lawrence8e397362014-01-27 15:22:30 -0800464 /** List of crypto types.
465 * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
466 * corresponding commands in CommandListener.cpp */
467 public static final String[] CRYPTO_TYPES
468 = { "password", "default", "pattern", "pin" };
469
Brian Carlstrom7395a8a2014-04-28 22:11:01 -0700470 private final Context mContext;
Jeff Sharkey5d0c55c2019-01-24 14:32:31 -0700471 private final ContentResolver mResolver;
Jeff Sharkeycd575992016-03-29 14:12:49 -0600472
Jeff Sharkey1019de92017-09-06 13:47:03 -0600473 private volatile IVold mVold;
Jin Qian12690d52017-10-13 18:17:04 -0700474 private volatile IStoraged mStoraged;
Jeff Sharkey1019de92017-09-06 13:47:03 -0600475
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900476 private volatile boolean mBootCompleted = false;
Jeff Sharkey48877892015-03-18 11:27:19 -0700477 private volatile boolean mDaemonConnected = false;
Jeff Sharkey9765e442017-12-14 22:15:14 -0700478 private volatile boolean mSecureKeyguardShowing = true;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700479
Sudheer Shanka0a541a52018-07-31 13:21:11 -0700480 private PackageManagerInternal mPmInternal;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700481
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -0800482 private IPackageManager mIPackageManager;
483 private IAppOpsService mIAppOpsService;
484
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700485 private final Callbacks mCallbacks;
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700486 private final LockPatternUtils mLockPatternUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -0700487
San Mehat6cdd9c02010-02-09 14:45:20 -0800488 /**
Kenny Root3b1abba2010-10-13 15:00:07 -0700489 * The size of the crypto algorithm key in bits for OBB files. Currently
490 * Twofish is used which takes 128-bit keys.
491 */
492 private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
493
494 /**
495 * The number of times to run SHA1 in the PBKDF2 function for OBB files.
496 * 1024 is reasonably secure and not too slow.
497 */
498 private static final int PBKDF2_HASH_ROUNDS = 1024;
499
500 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700501 * Mounted OBB tracking information. Used to track the current state of all
502 * OBBs.
Kenny Root02c87302010-07-01 08:10:18 -0700503 */
Kenny Root735de3b2010-09-30 14:11:39 -0700504 final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700505
506 /** Map from raw paths to {@link ObbState}. */
Kenny Roota02b8b02010-08-05 16:14:17 -0700507 final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
508
Svet Ganov6ee871e2015-07-10 14:29:33 -0700509 // Not guarded by a lock.
Sudheer Shanka2250d562016-11-07 15:41:02 -0800510 private final StorageManagerInternalImpl mStorageManagerInternal
511 = new StorageManagerInternalImpl();
Svet Ganov6ee871e2015-07-10 14:29:33 -0700512
Zim42f1e9f2019-08-15 17:35:00 +0100513 // Not guarded by a lock.
514 private final StorageSessionController mStorageSessionController;
515
Zim17be6f92019-09-25 14:37:55 +0100516 private final boolean mIsFuseEnabled;
517
Kenny Roota02b8b02010-08-05 16:14:17 -0700518 class ObbState implements IBinder.DeathRecipient {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700519 public ObbState(String rawPath, String canonicalPath, int callingUid,
Jeff Sharkey41cd6812017-09-11 10:32:17 -0600520 IObbActionListener token, int nonce, String volId) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700521 this.rawPath = rawPath;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700522 this.canonicalPath = canonicalPath;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700523 this.ownerGid = UserHandle.getSharedAppGid(callingUid);
Kenny Rootaf9d6672010-10-08 09:21:39 -0700524 this.token = token;
525 this.nonce = nonce;
Jeff Sharkey41cd6812017-09-11 10:32:17 -0600526 this.volId = volId;
Kenny Roota02b8b02010-08-05 16:14:17 -0700527 }
528
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700529 final String rawPath;
530 final String canonicalPath;
Kenny Roota02b8b02010-08-05 16:14:17 -0700531
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700532 final int ownerGid;
Kenny Roota02b8b02010-08-05 16:14:17 -0700533
Kenny Rootaf9d6672010-10-08 09:21:39 -0700534 // Token of remote Binder caller
535 final IObbActionListener token;
536
537 // Identifier to pass back to the token
538 final int nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700539
Jeff Sharkey41cd6812017-09-11 10:32:17 -0600540 String volId;
541
Kenny Root735de3b2010-09-30 14:11:39 -0700542 public IBinder getBinder() {
543 return token.asBinder();
544 }
545
Kenny Roota02b8b02010-08-05 16:14:17 -0700546 @Override
547 public void binderDied() {
548 ObbAction action = new UnmountObbAction(this, true);
549 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root735de3b2010-09-30 14:11:39 -0700550 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700551
Kenny Root5919ac62010-10-05 09:49:40 -0700552 public void link() throws RemoteException {
553 getBinder().linkToDeath(this, 0);
554 }
555
556 public void unlink() {
Kenny Root735de3b2010-09-30 14:11:39 -0700557 getBinder().unlinkToDeath(this, 0);
Kenny Roota02b8b02010-08-05 16:14:17 -0700558 }
Kenny Root38cf8862010-09-26 14:18:51 -0700559
560 @Override
561 public String toString() {
562 StringBuilder sb = new StringBuilder("ObbState{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700563 sb.append("rawPath=").append(rawPath);
564 sb.append(",canonicalPath=").append(canonicalPath);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700565 sb.append(",ownerGid=").append(ownerGid);
566 sb.append(",token=").append(token);
567 sb.append(",binder=").append(getBinder());
Jeff Sharkey41cd6812017-09-11 10:32:17 -0600568 sb.append(",volId=").append(volId);
Kenny Root38cf8862010-09-26 14:18:51 -0700569 sb.append('}');
570 return sb.toString();
571 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700572 }
573
574 // OBB Action Handler
575 final private ObbActionHandler mObbActionHandler;
576
577 // OBB action handler messages
578 private static final int OBB_RUN_ACTION = 1;
Sudheer Shanka25469aa2018-08-27 15:50:23 -0700579 private static final int OBB_FLUSH_MOUNT_STATE = 2;
Kenny Root02c87302010-07-01 08:10:18 -0700580
Christopher Tate7265abe2014-11-21 13:54:45 -0800581 // Last fstrim operation tracking
582 private static final String LAST_FSTRIM_FILE = "last-fstrim";
583 private final File mLastMaintenanceFile;
584 private long mLastMaintenance;
585
Kenny Root02c87302010-07-01 08:10:18 -0700586 // Handler messages
Jeff Sharkey48877892015-03-18 11:27:19 -0700587 private static final int H_SYSTEM_READY = 1;
588 private static final int H_DAEMON_CONNECTED = 2;
589 private static final int H_SHUTDOWN = 3;
590 private static final int H_FSTRIM = 4;
591 private static final int H_VOLUME_MOUNT = 5;
592 private static final int H_VOLUME_BROADCAST = 6;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700593 private static final int H_INTERNAL_BROADCAST = 7;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700594 private static final int H_VOLUME_UNMOUNT = 8;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800595 private static final int H_PARTITION_FORGET = 9;
596 private static final int H_RESET = 10;
Jin Qiana85b9912017-10-17 15:48:18 -0700597 private static final int H_RUN_IDLE_MAINT = 11;
598 private static final int H_ABORT_IDLE_MAINT = 12;
Daniel Rosenberg137aed12019-03-15 18:41:11 -0700599 private static final int H_BOOT_COMPLETED = 13;
Narayan Kamath157dd1d2019-06-12 13:06:30 +0100600 private static final int H_COMPLETE_UNLOCK_USER = 14;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800601
Sudheer Shanka2250d562016-11-07 15:41:02 -0800602 class StorageManagerServiceHandler extends Handler {
603 public StorageManagerServiceHandler(Looper looper) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700604 super(looper);
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400605 }
606
Jason parks5af0b912010-11-29 09:05:25 -0600607 @Override
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800608 public void handleMessage(Message msg) {
609 switch (msg.what) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700610 case H_SYSTEM_READY: {
Jeff Sharkey48877892015-03-18 11:27:19 -0700611 handleSystemReady();
612 break;
613 }
Daniel Rosenberg137aed12019-03-15 18:41:11 -0700614 case H_BOOT_COMPLETED: {
615 handleBootCompleted();
616 break;
617 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700618 case H_DAEMON_CONNECTED: {
619 handleDaemonConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700620 break;
621 }
Christopher Tated417d622013-08-19 16:14:25 -0700622 case H_FSTRIM: {
Christopher Tated417d622013-08-19 16:14:25 -0700623 Slog.i(TAG, "Running fstrim idle maintenance");
Christopher Tate7265abe2014-11-21 13:54:45 -0800624
625 // Remember when we kicked it off
626 try {
627 mLastMaintenance = System.currentTimeMillis();
628 mLastMaintenanceFile.setLastModified(mLastMaintenance);
629 } catch (Exception e) {
630 Slog.e(TAG, "Unable to record last fstrim!");
631 }
632
Jeff Sharkeyb302c542017-09-15 12:57:59 -0600633 // TODO: Reintroduce shouldBenchmark() test
Jeff Sharkey7e19f532017-11-06 13:54:11 -0700634 fstrim(0, null);
Christopher Tate7265abe2014-11-21 13:54:45 -0800635
Christopher Tated417d622013-08-19 16:14:25 -0700636 // invoke the completion callback, if any
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700637 // TODO: fstrim is non-blocking, so remove this useless callback
Christopher Tated417d622013-08-19 16:14:25 -0700638 Runnable callback = (Runnable) msg.obj;
639 if (callback != null) {
640 callback.run();
641 }
642 break;
643 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700644 case H_SHUTDOWN: {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800645 final IStorageShutdownObserver obs = (IStorageShutdownObserver) msg.obj;
Jeff Sharkey48877892015-03-18 11:27:19 -0700646 boolean success = false;
647 try {
Jeff Sharkey54402792017-09-15 16:05:19 -0600648 mVold.shutdown();
649 success = true;
Jeff Sharkeyace874b2017-09-07 15:27:33 -0600650 } catch (Exception e) {
651 Slog.wtf(TAG, e);
Jeff Sharkey48877892015-03-18 11:27:19 -0700652 }
653 if (obs != null) {
654 try {
655 obs.onShutDownComplete(success ? 0 : -1);
Jeff Sharkeyace874b2017-09-07 15:27:33 -0600656 } catch (Exception ignored) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700657 }
658 }
659 break;
660 }
661 case H_VOLUME_MOUNT: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700662 final VolumeInfo vol = (VolumeInfo) msg.obj;
Jeff Sharkey2e606d72015-07-27 14:19:54 -0700663 if (isMountDisallowed(vol)) {
664 Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");
665 break;
666 }
Zim42f1e9f2019-08-15 17:35:00 +0100667
Zim17be6f92019-09-25 14:37:55 +0100668 mount(vol);
Jeff Sharkey48877892015-03-18 11:27:19 -0700669 break;
670 }
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700671 case H_VOLUME_UNMOUNT: {
672 final VolumeInfo vol = (VolumeInfo) msg.obj;
Sudheer Shanka3f0645b2018-09-18 13:07:59 -0700673 unmount(vol);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700674 break;
675 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700676 case H_VOLUME_BROADCAST: {
677 final StorageVolume userVol = (StorageVolume) msg.obj;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700678 final String envState = userVol.getState();
679 Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + envState + " to "
Jeff Sharkey48877892015-03-18 11:27:19 -0700680 + userVol.getOwner());
681
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700682 final String action = VolumeInfo.getBroadcastForEnvironment(envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700683 if (action != null) {
684 final Intent intent = new Intent(action,
685 Uri.fromFile(userVol.getPathFile()));
686 intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, userVol);
Jeff Sharkey082f83b2017-03-26 14:34:47 -0600687 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
688 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Jeff Sharkey48877892015-03-18 11:27:19 -0700689 mContext.sendBroadcastAsUser(intent, userVol.getOwner());
690 }
691 break;
692 }
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700693 case H_INTERNAL_BROADCAST: {
694 // Internal broadcasts aimed at system components, not for
695 // third-party apps.
696 final Intent intent = (Intent) msg.obj;
697 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
698 android.Manifest.permission.WRITE_MEDIA_STORAGE);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800699 break;
700 }
701 case H_PARTITION_FORGET: {
Jeff Sharkeydb4b6192017-10-24 11:08:50 -0600702 final VolumeRecord rec = (VolumeRecord) msg.obj;
703 forgetPartition(rec.partGuid, rec.fsUuid);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800704 break;
705 }
706 case H_RESET: {
Daniel Rosenberg137aed12019-03-15 18:41:11 -0700707 resetIfBootedAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800708 break;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700709 }
Jin Qiana85b9912017-10-17 15:48:18 -0700710 case H_RUN_IDLE_MAINT: {
711 Slog.i(TAG, "Running idle maintenance");
712 runIdleMaint((Runnable)msg.obj);
713 break;
714 }
715 case H_ABORT_IDLE_MAINT: {
716 Slog.i(TAG, "Aborting idle maintenance");
717 abortIdleMaint((Runnable)msg.obj);
718 break;
719 }
Narayan Kamath157dd1d2019-06-12 13:06:30 +0100720 case H_COMPLETE_UNLOCK_USER: {
721 completeUnlockUser((int) msg.obj);
722 break;
723 }
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800724 }
725 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700726 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700727
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700728 private final Handler mHandler;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800729
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700730 private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
731 @Override
732 public void onReceive(Context context, Intent intent) {
733 final String action = intent.getAction();
734 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700735 Preconditions.checkArgument(userId >= 0);
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700736
737 try {
738 if (Intent.ACTION_USER_ADDED.equals(action)) {
739 final UserManager um = mContext.getSystemService(UserManager.class);
740 final int userSerialNumber = um.getUserSerialNumber(userId);
Jeff Sharkey54402792017-09-15 16:05:19 -0600741 mVold.onUserAdded(userId, userSerialNumber);
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700742 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700743 synchronized (mVolumes) {
744 final int size = mVolumes.size();
745 for (int i = 0; i < size; i++) {
746 final VolumeInfo vol = mVolumes.valueAt(i);
747 if (vol.mountUserId == userId) {
748 vol.mountUserId = UserHandle.USER_NULL;
749 mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
750 }
751 }
752 }
Jeff Sharkey54402792017-09-15 16:05:19 -0600753 mVold.onUserRemoved(userId);
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700754 }
Jeff Sharkeyace874b2017-09-07 15:27:33 -0600755 } catch (Exception e) {
756 Slog.wtf(TAG, e);
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700757 }
758 }
759 };
760
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700761 private void waitForLatch(CountDownLatch latch, String condition, long timeoutMillis)
762 throws TimeoutException {
763 final long startMillis = SystemClock.elapsedRealtime();
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700764 while (true) {
Kenny Root51a573c2012-05-17 13:30:28 -0700765 try {
766 if (latch.await(5000, TimeUnit.MILLISECONDS)) {
San Mehat207e5382010-02-04 20:46:54 -0800767 return;
Kenny Root51a573c2012-05-17 13:30:28 -0700768 } else {
769 Slog.w(TAG, "Thread " + Thread.currentThread().getName()
Jeff Sharkey48877892015-03-18 11:27:19 -0700770 + " still waiting for " + condition + "...");
San Mehat207e5382010-02-04 20:46:54 -0800771 }
Kenny Root51a573c2012-05-17 13:30:28 -0700772 } catch (InterruptedException e) {
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700773 Slog.w(TAG, "Interrupt while waiting for " + condition);
San Mehat207e5382010-02-04 20:46:54 -0800774 }
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700775 if (timeoutMillis > 0 && SystemClock.elapsedRealtime() > startMillis + timeoutMillis) {
776 throw new TimeoutException("Thread " + Thread.currentThread().getName()
777 + " gave up waiting for " + condition + " after " + timeoutMillis + "ms");
778 }
San Mehat207e5382010-02-04 20:46:54 -0800779 }
San Mehat1f6301e2010-01-07 22:40:27 -0800780 }
Kenny Root02c87302010-07-01 08:10:18 -0700781
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700782 private void handleSystemReady() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700783 // Start scheduling nominally-daily fstrim operations
Christopher Tate115afda2014-06-06 19:06:26 -0700784 MountServiceIdler.scheduleIdlePass(mContext);
Daniel Colascione766b6322018-01-08 19:10:36 -0800785
786 // Toggle zram-enable system property in response to settings
787 mContext.getContentResolver().registerContentObserver(
788 Settings.Global.getUriFor(Settings.Global.ZRAM_ENABLED),
789 false /*notifyForDescendants*/,
790 new ContentObserver(null /* current thread */) {
791 @Override
792 public void onChange(boolean selfChange) {
793 refreshZramSettings();
794 }
795 });
796 refreshZramSettings();
Jeff Sharkeyb0c363b22018-12-15 11:53:03 -0700797
Srinivas Paladuguc8261752019-01-09 10:54:52 -0800798 // Schedule zram writeback unless zram is disabled by persist.sys.zram_enabled
799 String zramPropValue = SystemProperties.get(ZRAM_ENABLED_PROPERTY);
800 if (!zramPropValue.equals("0")
801 && mContext.getResources().getBoolean(
802 com.android.internal.R.bool.config_zramWriteback)) {
803 ZramWriteback.scheduleZramWriteback(mContext);
804 }
Jeff Sharkeyb0c363b22018-12-15 11:53:03 -0700805 // Toggle isolated-enable system property in response to settings
806 mContext.getContentResolver().registerContentObserver(
807 Settings.Global.getUriFor(Settings.Global.ISOLATED_STORAGE_REMOTE),
808 false /*notifyForDescendants*/,
809 new ContentObserver(null /* current thread */) {
810 @Override
811 public void onChange(boolean selfChange) {
812 refreshIsolatedStorageSettings();
813 }
814 });
Jeff Sharkey5d0c55c2019-01-24 14:32:31 -0700815 // For now, simply clone property when it changes
shafik91b34612019-09-23 15:41:44 +0100816 DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
Matt Pape15769e22019-04-19 12:31:24 -0700817 mContext.getMainExecutor(), (properties) -> {
Jeff Sharkey8b499a02019-01-28 13:31:50 -0700818 refreshIsolatedStorageSettings();
shafikb2992b62019-10-01 15:31:02 +0100819 refreshFuseSettings();
Jeff Sharkey5d0c55c2019-01-24 14:32:31 -0700820 });
Jeff Sharkeyb0c363b22018-12-15 11:53:03 -0700821 refreshIsolatedStorageSettings();
Daniel Colascione766b6322018-01-08 19:10:36 -0800822 }
823
824 /**
825 * Update the zram_enabled system property (which init reads to
826 * decide whether to enable zram) to reflect the zram_enabled
827 * preference (which we can change for experimentation purposes).
828 */
829 private void refreshZramSettings() {
830 String propertyValue = SystemProperties.get(ZRAM_ENABLED_PROPERTY);
831 if ("".equals(propertyValue)) {
832 return; // System doesn't have zram toggling support
833 }
834 String desiredPropertyValue =
835 Settings.Global.getInt(mContext.getContentResolver(),
836 Settings.Global.ZRAM_ENABLED,
837 1) != 0
838 ? "1" : "0";
839 if (!desiredPropertyValue.equals(propertyValue)) {
840 // Avoid redundant disk writes by setting only if we're
841 // changing the property value. There's no race: we're the
842 // sole writer.
843 SystemProperties.set(ZRAM_ENABLED_PROPERTY, desiredPropertyValue);
Srinivas Paladuguc8261752019-01-09 10:54:52 -0800844 // Schedule writeback only if zram is being enabled.
845 if (desiredPropertyValue.equals("1")
846 && mContext.getResources().getBoolean(
847 com.android.internal.R.bool.config_zramWriteback)) {
848 ZramWriteback.scheduleZramWriteback(mContext);
849 }
Daniel Colascione766b6322018-01-08 19:10:36 -0800850 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700851 }
852
Jeff Sharkeyb0c363b22018-12-15 11:53:03 -0700853 private void refreshIsolatedStorageSettings() {
Jeff Sharkey8b499a02019-01-28 13:31:50 -0700854 // Always copy value from newer DeviceConfig location
855 Settings.Global.putString(mResolver,
856 Settings.Global.ISOLATED_STORAGE_REMOTE,
shafik91b34612019-09-23 15:41:44 +0100857 DeviceConfig.getProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
858 ISOLATED_STORAGE_ENABLED));
Jeff Sharkey8b499a02019-01-28 13:31:50 -0700859
Jeff Sharkeyb0c363b22018-12-15 11:53:03 -0700860 final int local = Settings.Global.getInt(mContext.getContentResolver(),
861 Settings.Global.ISOLATED_STORAGE_LOCAL, 0);
862 final int remote = Settings.Global.getInt(mContext.getContentResolver(),
863 Settings.Global.ISOLATED_STORAGE_REMOTE, 0);
864
865 // Walk down precedence chain; we prefer local settings first, then
866 // remote settings, before finally falling back to hard-coded default.
867 final boolean res;
868 if (local == -1) {
869 res = false;
870 } else if (local == 1) {
871 res = true;
872 } else if (remote == -1) {
873 res = false;
874 } else if (remote == 1) {
875 res = true;
876 } else {
Jeff Sharkey06376802019-02-11 12:20:02 -0700877 res = true;
Jeff Sharkeyb0c363b22018-12-15 11:53:03 -0700878 }
879
880 Slog.d(TAG, "Isolated storage local flag " + local + " and remote flag "
881 + remote + " resolved to " + res);
882 SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE, Boolean.toString(res));
883 }
884
Abhijeet Kaurb9847712019-11-19 16:35:47 +0000885 /**
886 * The most recent flag change takes precedence. Change fuse Settings flag if Device Config is
887 * changed. Settings flag change will in turn change fuse system property (persist.sys.fuse)
888 * whenever the user reboots.
889 */
shafikb2992b62019-10-01 15:31:02 +0100890 private void refreshFuseSettings() {
891 int isFuseEnabled = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
892 FUSE_ENABLED, 0);
893 if (isFuseEnabled == 1) {
Abhijeet Kaurb9847712019-11-19 16:35:47 +0000894 Slog.d(TAG, "Device Config flag for FUSE is enabled, turn Settings fuse flag on");
895 SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX
896 + FeatureFlagUtils.SETTINGS_FUSE_FLAG, "true");
shafikb2992b62019-10-01 15:31:02 +0100897 } else if (isFuseEnabled == -1) {
Abhijeet Kaurb9847712019-11-19 16:35:47 +0000898 Slog.d(TAG, "Device Config flag for FUSE is disabled, turn Settings fuse flag off");
899 SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX
900 + FeatureFlagUtils.SETTINGS_FUSE_FLAG, "false");
shafikb2992b62019-10-01 15:31:02 +0100901 }
902 // else, keep the build config.
Abhijeet Kaurb9847712019-11-19 16:35:47 +0000903 // This can be overridden by direct adjustment of persist.sys.fflag.override.settings_fuse
shafikb2992b62019-10-01 15:31:02 +0100904 }
905
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700906 /**
907 * MediaProvider has a ton of code that makes assumptions about storage
908 * paths never changing, so we outright kill them to pick up new state.
909 */
910 @Deprecated
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700911 private void killMediaProvider(List<UserInfo> users) {
912 if (users == null) return;
913
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700914 final long token = Binder.clearCallingIdentity();
915 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700916 for (UserInfo user : users) {
917 // System user does not have media provider, so skip.
918 if (user.isSystemOnly()) continue;
919
Jeff Sharkey5790af02018-08-13 17:42:54 -0600920 final ProviderInfo provider = mPmInternal.resolveContentProvider(
921 MediaStore.AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE
Jeff Sharkey8a372a02016-03-16 16:25:45 -0600922 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
923 user.id);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700924 if (provider != null) {
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800925 final IActivityManager am = ActivityManager.getService();
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700926 try {
Jeff Sharkey85f449e2016-06-23 09:26:00 -0600927 am.killApplication(provider.applicationInfo.packageName,
928 UserHandle.getAppId(provider.applicationInfo.uid),
929 UserHandle.USER_ALL, "vold reset");
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700930 // We only need to run this once. It will kill all users' media processes.
931 break;
932 } catch (RemoteException e) {
933 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700934 }
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700935 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700936 } finally {
937 Binder.restoreCallingIdentity(token);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700938 }
939 }
940
Andreas Gampea36dc622018-02-05 17:19:22 -0800941 @GuardedBy("mLock")
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800942 private void addInternalVolumeLocked() {
Amith Yamasania7892482015-08-07 11:09:05 -0700943 // Create a stub volume that represents internal storage
944 final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
945 VolumeInfo.TYPE_PRIVATE, null, null);
946 internal.state = VolumeInfo.STATE_MOUNTED;
947 internal.path = Environment.getDataDirectory().getAbsolutePath();
948 mVolumes.put(internal.id, internal);
949 }
950
Daniel Rosenberg137aed12019-03-15 18:41:11 -0700951 private void initIfBootedAndConnected() {
952 Slog.d(TAG, "Thinking about init, mBootCompleted=" + mBootCompleted
Jeff Sharkey8924e872015-11-30 12:52:10 -0700953 + ", mDaemonConnected=" + mDaemonConnected);
Eric Biggers1127d922019-04-05 12:46:35 -0700954 if (mBootCompleted && mDaemonConnected
955 && !StorageManager.isFileEncryptedNativeOnly()) {
956 // When booting a device without native support, make sure that our
957 // user directories are locked or unlocked based on the current
958 // emulation status.
959 final boolean initLocked = StorageManager.isFileEncryptedEmulatedOnly();
960 Slog.d(TAG, "Setting up emulation state, initlocked=" + initLocked);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700961 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Jeff Sharkey8924e872015-11-30 12:52:10 -0700962 for (UserInfo user : users) {
963 try {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700964 if (initLocked) {
Jeff Sharkey54402792017-09-15 16:05:19 -0600965 mVold.lockUserKey(user.id);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700966 } else {
Jeff Sharkey54402792017-09-15 16:05:19 -0600967 mVold.unlockUserKey(user.id, user.serialNumber, encodeBytes(null),
968 encodeBytes(null));
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700969 }
Jeff Sharkey43e12112017-09-12 16:31:45 -0600970 } catch (Exception e) {
971 Slog.wtf(TAG, e);
Jeff Sharkey8924e872015-11-30 12:52:10 -0700972 }
973 }
974 }
975 }
976
Daniel Rosenberg137aed12019-03-15 18:41:11 -0700977 private void resetIfBootedAndConnected() {
978 Slog.d(TAG, "Thinking about reset, mBootCompleted=" + mBootCompleted
Jeff Sharkey48877892015-03-18 11:27:19 -0700979 + ", mDaemonConnected=" + mDaemonConnected);
Daniel Rosenberg137aed12019-03-15 18:41:11 -0700980 if (mBootCompleted && mDaemonConnected) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800981 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Zim17be6f92019-09-25 14:37:55 +0100982
983 if (mIsFuseEnabled) {
984 mStorageSessionController.onReset(mVold, mHandler);
985 } else {
986 killMediaProvider(users);
987 }
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700988
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700989 final int[] systemUnlockedUsers;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800990 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700991 systemUnlockedUsers = mSystemUnlockedUsers;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700992
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800993 mDisks.clear();
994 mVolumes.clear();
995
996 addInternalVolumeLocked();
997 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700998
Jeff Sharkey48877892015-03-18 11:27:19 -0700999 try {
Zim42f1e9f2019-08-15 17:35:00 +01001000 // TODO(b/135341433): Remove paranoid logging when FUSE is stable
Zim17be6f92019-09-25 14:37:55 +01001001 Slog.i(TAG, "Resetting vold...");
Jeff Sharkey54402792017-09-15 16:05:19 -06001002 mVold.reset();
Zim42f1e9f2019-08-15 17:35:00 +01001003 Slog.i(TAG, "Reset vold");
Jeff Sharkeybcd262d2015-06-10 09:41:17 -07001004
1005 // Tell vold about all existing and started users
Jeff Sharkeybcd262d2015-06-10 09:41:17 -07001006 for (UserInfo user : users) {
Jeff Sharkey54402792017-09-15 16:05:19 -06001007 mVold.onUserAdded(user.id, user.serialNumber);
Jeff Sharkeybcd262d2015-06-10 09:41:17 -07001008 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001009 for (int userId : systemUnlockedUsers) {
Sudheer Shanka64501e52019-04-29 10:46:26 -07001010 mVold.onUserStarted(userId);
Jin Qian12690d52017-10-13 18:17:04 -07001011 mStoraged.onUserStarted(userId);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001012 }
Jeff Sharkey9765e442017-12-14 22:15:14 -07001013 mVold.onSecureKeyguardStateChanged(mSecureKeyguardShowing);
Risanaec0ee72018-10-31 10:10:12 +09001014 mStorageManagerInternal.onReset(mVold);
Jeff Sharkeyace874b2017-09-07 15:27:33 -06001015 } catch (Exception e) {
1016 Slog.wtf(TAG, e);
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001017 }
1018 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001019 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001020
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001021 private void onUnlockUser(int userId) {
1022 Slog.d(TAG, "onUnlockUser " + userId);
Jeff Sharkey48877892015-03-18 11:27:19 -07001023
1024 // We purposefully block here to make sure that user-specific
1025 // staging area is ready so it's ready for zygote-forked apps to
1026 // bind mount against.
1027 try {
Zim17be6f92019-09-25 14:37:55 +01001028 mStorageSessionController.onUnlockUser(userId);
Sudheer Shanka64501e52019-04-29 10:46:26 -07001029 mVold.onUserStarted(userId);
Jin Qian12690d52017-10-13 18:17:04 -07001030 mStoraged.onUserStarted(userId);
Jeff Sharkeyace874b2017-09-07 15:27:33 -06001031 } catch (Exception e) {
1032 Slog.wtf(TAG, e);
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001033 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001034
Narayan Kamath157dd1d2019-06-12 13:06:30 +01001035 mHandler.obtainMessage(H_COMPLETE_UNLOCK_USER, userId).sendToTarget();
1036 }
1037
1038 private void completeUnlockUser(int userId) {
1039 // If user 0 has completed unlock, perform a one-time migration of legacy obb data
1040 // to its new location. This may take time depending on the size of the data to be copied
1041 // so it's done on the StorageManager handler thread.
1042 if (userId == 0) {
1043 mPmInternal.migrateLegacyObbData();
1044 }
1045
Jeff Sharkey48877892015-03-18 11:27:19 -07001046 // Record user as started so newly mounted volumes kick off events
1047 // correctly, then synthesize events for any already-mounted volumes.
yuanhuihuiefd1f122016-07-13 21:21:03 +08001048 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001049 for (int i = 0; i < mVolumes.size(); i++) {
1050 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey46349872015-07-28 10:49:47 -07001051 if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001052 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey48877892015-03-18 11:27:19 -07001053 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001054
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001055 final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
1056 mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
Jeff Sharkey48877892015-03-18 11:27:19 -07001057 }
1058 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001059 mSystemUnlockedUsers = ArrayUtils.appendInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -07001060 }
1061 }
1062
1063 private void onCleanupUser(int userId) {
1064 Slog.d(TAG, "onCleanupUser " + userId);
1065
1066 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06001067 mVold.onUserStopped(userId);
Jin Qian12690d52017-10-13 18:17:04 -07001068 mStoraged.onUserStopped(userId);
Jeff Sharkeyace874b2017-09-07 15:27:33 -06001069 } catch (Exception e) {
1070 Slog.wtf(TAG, e);
Jeff Sharkey48877892015-03-18 11:27:19 -07001071 }
1072
yuanhuihuiefd1f122016-07-13 21:21:03 +08001073 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001074 mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -07001075 }
1076 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001077
Sudheer Shanka64501e52019-04-29 10:46:26 -07001078 private boolean supportsBlockCheckpoint() throws RemoteException {
Paul Lawrence15a54462019-04-30 11:14:25 -07001079 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Sandeep Patil7d5c4912019-04-15 09:27:30 -07001080 return mVold.supportsBlockCheckpoint();
1081 }
1082
Jeff Sharkey9765e442017-12-14 22:15:14 -07001083 @Override
1084 public void onAwakeStateChanged(boolean isAwake) {
1085 // Ignored
1086 }
1087
1088 @Override
1089 public void onKeyguardStateChanged(boolean isShowing) {
1090 // Push down current secure keyguard status so that we ignore malicious
1091 // USB devices while locked.
1092 mSecureKeyguardShowing = isShowing
1093 && mContext.getSystemService(KeyguardManager.class).isDeviceSecure();
1094 try {
1095 mVold.onSecureKeyguardStateChanged(mSecureKeyguardShowing);
1096 } catch (Exception e) {
1097 Slog.wtf(TAG, e);
1098 }
1099 }
1100
Christopher Tated417d622013-08-19 16:14:25 -07001101 void runIdleMaintenance(Runnable callback) {
1102 mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
1103 }
1104
Christopher Tate7265abe2014-11-21 13:54:45 -08001105 // Binder entry point for kicking off an immediate fstrim
1106 @Override
1107 public void runMaintenance() {
Jeff Sharkey48877892015-03-18 11:27:19 -07001108 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Christopher Tate7265abe2014-11-21 13:54:45 -08001109 runIdleMaintenance(null);
1110 }
1111
1112 @Override
1113 public long lastMaintenance() {
1114 return mLastMaintenance;
1115 }
1116
San Mehat4270e1e2010-01-29 05:32:19 -08001117 public void onDaemonConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -07001118 mDaemonConnected = true;
1119 mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();
1120 }
1121
1122 private void handleDaemonConnected() {
Daniel Rosenberg137aed12019-03-15 18:41:11 -07001123 initIfBootedAndConnected();
1124 resetIfBootedAndConnected();
Jeff Sharkey48877892015-03-18 11:27:19 -07001125
Jeff Sharkey48877892015-03-18 11:27:19 -07001126 // On an encrypted device we can't see system properties yet, so pull
1127 // the system locale out of the mount service.
Inseob Kimc1246e62018-11-08 13:13:54 +09001128 if ("".equals(VoldProperties.encrypt_progress().orElse(""))) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001129 copyLocaleFromMountService();
1130 }
San Mehat4270e1e2010-01-29 05:32:19 -08001131 }
1132
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001133 private void copyLocaleFromMountService() {
1134 String systemLocale;
1135 try {
1136 systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
1137 } catch (RemoteException e) {
1138 return;
1139 }
1140 if (TextUtils.isEmpty(systemLocale)) {
1141 return;
1142 }
1143
1144 Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
1145 Locale locale = Locale.forLanguageTag(systemLocale);
1146 Configuration config = new Configuration();
1147 config.setLocale(locale);
1148 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001149 ActivityManager.getService().updatePersistentConfiguration(config);
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001150 } catch (RemoteException e) {
1151 Slog.e(TAG, "Error setting system locale from mount service", e);
1152 }
Elliott Hughes9c33f282014-10-13 12:39:56 -07001153
1154 // Temporary workaround for http://b/17945169.
1155 Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
Narayan Kamathd30dbb82015-01-15 14:48:15 +00001156 SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001157 }
1158
Jeff Sharkey8058fe62017-09-13 11:50:33 -06001159 private final IVoldListener mListener = new IVoldListener.Stub() {
1160 @Override
1161 public void onDiskCreated(String diskId, int flags) {
1162 synchronized (mLock) {
Jeff Sharkey901c0422018-04-20 13:11:20 -06001163 final String value = SystemProperties.get(StorageManager.PROP_ADOPTABLE);
1164 switch (value) {
1165 case "force_on":
1166 flags |= DiskInfo.FLAG_ADOPTABLE;
1167 break;
1168 case "force_off":
1169 flags &= ~DiskInfo.FLAG_ADOPTABLE;
1170 break;
Jeff Sharkey8058fe62017-09-13 11:50:33 -06001171 }
Jeff Sharkey8058fe62017-09-13 11:50:33 -06001172 mDisks.put(diskId, new DiskInfo(diskId, flags));
1173 }
1174 }
1175
1176 @Override
1177 public void onDiskScanned(String diskId) {
1178 synchronized (mLock) {
1179 final DiskInfo disk = mDisks.get(diskId);
1180 if (disk != null) {
1181 onDiskScannedLocked(disk);
1182 }
1183 }
1184 }
1185
1186 @Override
1187 public void onDiskMetadataChanged(String diskId, long sizeBytes, String label,
1188 String sysPath) {
1189 synchronized (mLock) {
1190 final DiskInfo disk = mDisks.get(diskId);
1191 if (disk != null) {
1192 disk.size = sizeBytes;
1193 disk.label = label;
1194 disk.sysPath = sysPath;
1195 }
1196 }
1197 }
1198
1199 @Override
1200 public void onDiskDestroyed(String diskId) {
1201 synchronized (mLock) {
1202 final DiskInfo disk = mDisks.remove(diskId);
1203 if (disk != null) {
1204 mCallbacks.notifyDiskDestroyed(disk);
1205 }
1206 }
1207 }
1208
1209 @Override
Zim17be6f92019-09-25 14:37:55 +01001210 public void onVolumeCreated(String volId, int type, String diskId, String partGuid,
1211 int userId) {
Jeff Sharkey8058fe62017-09-13 11:50:33 -06001212 synchronized (mLock) {
1213 final DiskInfo disk = mDisks.get(diskId);
1214 final VolumeInfo vol = new VolumeInfo(volId, type, disk, partGuid);
Zim17be6f92019-09-25 14:37:55 +01001215 vol.mountUserId = userId;
Jeff Sharkey8058fe62017-09-13 11:50:33 -06001216 mVolumes.put(volId, vol);
1217 onVolumeCreatedLocked(vol);
1218 }
1219 }
1220
1221 @Override
1222 public void onVolumeStateChanged(String volId, int state) {
1223 synchronized (mLock) {
1224 final VolumeInfo vol = mVolumes.get(volId);
1225 if (vol != null) {
1226 final int oldState = vol.state;
1227 final int newState = state;
1228 vol.state = newState;
1229 onVolumeStateChangedLocked(vol, oldState, newState);
1230 }
1231 }
1232 }
1233
1234 @Override
1235 public void onVolumeMetadataChanged(String volId, String fsType, String fsUuid,
1236 String fsLabel) {
1237 synchronized (mLock) {
1238 final VolumeInfo vol = mVolumes.get(volId);
1239 if (vol != null) {
1240 vol.fsType = fsType;
1241 vol.fsUuid = fsUuid;
1242 vol.fsLabel = fsLabel;
1243 }
1244 }
1245 }
1246
1247 @Override
1248 public void onVolumePathChanged(String volId, String path) {
1249 synchronized (mLock) {
1250 final VolumeInfo vol = mVolumes.get(volId);
1251 if (vol != null) {
1252 vol.path = path;
1253 }
1254 }
1255 }
1256
1257 @Override
1258 public void onVolumeInternalPathChanged(String volId, String internalPath) {
1259 synchronized (mLock) {
1260 final VolumeInfo vol = mVolumes.get(volId);
1261 if (vol != null) {
1262 vol.internalPath = internalPath;
1263 }
1264 }
1265 }
1266
1267 @Override
1268 public void onVolumeDestroyed(String volId) {
Zim17be6f92019-09-25 14:37:55 +01001269 VolumeInfo vol = null;
Jeff Sharkey8058fe62017-09-13 11:50:33 -06001270 synchronized (mLock) {
Zim17be6f92019-09-25 14:37:55 +01001271 vol = mVolumes.remove(volId);
1272 }
1273
1274 if (vol != null) {
1275 mStorageSessionController.onVolumeRemove(vol);
Jeff Sharkey8058fe62017-09-13 11:50:33 -06001276 }
1277 }
1278 };
1279
Andreas Gampea36dc622018-02-05 17:19:22 -08001280 @GuardedBy("mLock")
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001281 private void onDiskScannedLocked(DiskInfo disk) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001282 int volumeCount = 0;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001283 for (int i = 0; i < mVolumes.size(); i++) {
1284 final VolumeInfo vol = mVolumes.valueAt(i);
1285 if (Objects.equals(disk.id, vol.getDiskId())) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001286 volumeCount++;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001287 }
1288 }
1289
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001290 final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
Jeff Sharkey7732e1e2016-03-30 17:14:23 -06001291 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1292 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001293 intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
1294 intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001295 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001296
1297 final CountDownLatch latch = mDiskScanLatches.remove(disk.id);
1298 if (latch != null) {
1299 latch.countDown();
1300 }
1301
Jeff Sharkeyf5a6bd72015-05-19 14:42:38 -07001302 disk.volumeCount = volumeCount;
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001303 mCallbacks.notifyDiskScanned(disk, volumeCount);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001304 }
1305
Andreas Gampea36dc622018-02-05 17:19:22 -08001306 @GuardedBy("mLock")
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001307 private void onVolumeCreatedLocked(VolumeInfo vol) {
Jeff Sharkey5790af02018-08-13 17:42:54 -06001308 if (mPmInternal.isOnlyCoreApps()) {
Jeff Sharkey6855c482016-03-31 14:34:38 -06001309 Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId());
1310 return;
1311 }
1312
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001313 if (vol.type == VolumeInfo.TYPE_EMULATED) {
1314 final StorageManager storage = mContext.getSystemService(StorageManager.class);
1315 final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
1316
1317 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
1318 && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
1319 Slog.v(TAG, "Found primary storage at " + vol);
1320 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1321 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1322 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1323
1324 } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
1325 Slog.v(TAG, "Found primary storage at " + vol);
1326 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1327 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1328 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1329 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001330
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001331 } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001332 // TODO: only look at first public partition
1333 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1334 && vol.disk.isDefaultPrimary()) {
1335 Slog.v(TAG, "Found primary storage at " + vol);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001336 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1337 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
San Mehat4270e1e2010-01-29 05:32:19 -08001338 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001339
1340 // Adoptable public disks are visible to apps, since they meet
1341 // public API requirement of being in a stable location.
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001342 if (vol.disk.isAdoptable()) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001343 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1344 }
1345
Jeff Sharkeyab15c392016-05-05 11:45:01 -06001346 vol.mountUserId = mCurrentUserId;
Jeff Sharkey48877892015-03-18 11:27:19 -07001347 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001348
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001349 } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1350 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1351
Risan05c41e62018-10-29 08:57:43 +09001352 } else if (vol.type == VolumeInfo.TYPE_STUB) {
1353 vol.mountUserId = mCurrentUserId;
1354 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001355 } else {
Jeff Sharkey48877892015-03-18 11:27:19 -07001356 Slog.d(TAG, "Skipping automatic mounting of " + vol);
San Mehat4270e1e2010-01-29 05:32:19 -08001357 }
1358 }
1359
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001360 private boolean isBroadcastWorthy(VolumeInfo vol) {
1361 switch (vol.getType()) {
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001362 case VolumeInfo.TYPE_PRIVATE:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001363 case VolumeInfo.TYPE_PUBLIC:
1364 case VolumeInfo.TYPE_EMULATED:
Risan05c41e62018-10-29 08:57:43 +09001365 case VolumeInfo.TYPE_STUB:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001366 break;
1367 default:
1368 return false;
1369 }
1370
1371 switch (vol.getState()) {
1372 case VolumeInfo.STATE_MOUNTED:
1373 case VolumeInfo.STATE_MOUNTED_READ_ONLY:
1374 case VolumeInfo.STATE_EJECTING:
1375 case VolumeInfo.STATE_UNMOUNTED:
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001376 case VolumeInfo.STATE_UNMOUNTABLE:
Tony Mantlerf0d71052015-06-24 11:45:25 -07001377 case VolumeInfo.STATE_BAD_REMOVAL:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001378 break;
1379 default:
1380 return false;
1381 }
1382
1383 return true;
1384 }
1385
Andreas Gampea36dc622018-02-05 17:19:22 -08001386 @GuardedBy("mLock")
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001387 private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001388 // Remember that we saw this volume so we're ready to accept user
1389 // metadata, or so we can annoy them when a private volume is ejected
Jeff Sharkey3811f352019-05-14 11:54:36 -06001390 if (!TextUtils.isEmpty(vol.fsUuid)) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001391 VolumeRecord rec = mRecords.get(vol.fsUuid);
1392 if (rec == null) {
1393 rec = new VolumeRecord(vol.type, vol.fsUuid);
1394 rec.partGuid = vol.partGuid;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001395 rec.createdMillis = System.currentTimeMillis();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001396 if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1397 rec.nickname = vol.disk.getDescription();
1398 }
1399 mRecords.put(rec.fsUuid, rec);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001400 } else {
1401 // Handle upgrade case where we didn't store partition GUID
1402 if (TextUtils.isEmpty(rec.partGuid)) {
1403 rec.partGuid = vol.partGuid;
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001404 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001405 }
Jeff Sharkey3811f352019-05-14 11:54:36 -06001406
1407 rec.lastSeenMillis = System.currentTimeMillis();
1408 writeSettingsLocked();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001409 }
1410
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001411 mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
1412
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001413 // Do not broadcast before boot has completed to avoid launching the
1414 // processes that receive the intent unnecessarily.
1415 if (mBootCompleted && isBroadcastWorthy(vol)) {
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001416 final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001417 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
1418 intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
Tony Mantlerf0d71052015-06-24 11:45:25 -07001419 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
Jeff Sharkey7732e1e2016-03-30 17:14:23 -06001420 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1421 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001422 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001423 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001424
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001425 final String oldStateEnv = VolumeInfo.getEnvironmentForState(oldState);
1426 final String newStateEnv = VolumeInfo.getEnvironmentForState(newState);
Emily Bernier92aa5a22014-07-07 10:11:48 -04001427
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001428 if (!Objects.equals(oldStateEnv, newStateEnv)) {
1429 // Kick state changed event towards all started users. Any users
1430 // started after this point will trigger additional
1431 // user-specific broadcasts.
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001432 for (int userId : mSystemUnlockedUsers) {
Jeff Sharkey46349872015-07-28 10:49:47 -07001433 if (vol.isVisibleForRead(userId)) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001434 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001435 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey48877892015-03-18 11:27:19 -07001436
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001437 mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
1438 newStateEnv);
San Mehat4270e1e2010-01-29 05:32:19 -08001439 }
1440 }
1441 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001442
Risan05c41e62018-10-29 08:57:43 +09001443 if ((vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_STUB)
1444 && vol.state == VolumeInfo.STATE_EJECTING) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001445 // TODO: this should eventually be handled by new ObbVolume state changes
1446 /*
1447 * Some OBBs might have been unmounted when this volume was
1448 * unmounted, so send a message to the handler to let it know to
1449 * remove those from the list of mounted OBBS.
1450 */
1451 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
1452 OBB_FLUSH_MOUNT_STATE, vol.path));
1453 }
Pavel Grafovce72ef02018-01-10 17:14:11 +00001454 maybeLogMediaMount(vol, newState);
1455 }
1456
1457 private void maybeLogMediaMount(VolumeInfo vol, int newState) {
1458 if (!SecurityLog.isLoggingEnabled()) {
1459 return;
1460 }
1461
1462 final DiskInfo disk = vol.getDisk();
1463 if (disk == null || (disk.flags & (DiskInfo.FLAG_SD | DiskInfo.FLAG_USB)) == 0) {
1464 return;
1465 }
1466
1467 // Sometimes there is a newline character.
1468 final String label = disk.label != null ? disk.label.trim() : "";
1469
1470 if (newState == VolumeInfo.STATE_MOUNTED
1471 || newState == VolumeInfo.STATE_MOUNTED_READ_ONLY) {
1472 SecurityLog.writeEvent(SecurityLog.TAG_MEDIA_MOUNT, vol.path, label);
1473 } else if (newState == VolumeInfo.STATE_UNMOUNTED
1474 || newState == VolumeInfo.STATE_BAD_REMOVAL) {
1475 SecurityLog.writeEvent(SecurityLog.TAG_MEDIA_UNMOUNT, vol.path, label);
1476 }
San Mehat4270e1e2010-01-29 05:32:19 -08001477 }
1478
Andreas Gampea36dc622018-02-05 17:19:22 -08001479 @GuardedBy("mLock")
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001480 private void onMoveStatusLocked(int status) {
1481 if (mMoveCallback == null) {
1482 Slog.w(TAG, "Odd, status but no move requested");
1483 return;
1484 }
1485
1486 // TODO: estimate remaining time
1487 try {
Jeff Sharkey50a05452015-04-29 11:24:52 -07001488 mMoveCallback.onStatusChanged(-1, status, -1);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001489 } catch (RemoteException ignored) {
1490 }
1491
1492 // We've finished copying and we're about to clean up old data, so
1493 // remember that move was successful if we get rebooted
1494 if (status == MOVE_STATUS_COPY_FINISHED) {
1495 Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
1496
1497 mPrimaryStorageUuid = mMoveTargetUuid;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001498 writeSettingsLocked();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001499 }
1500
1501 if (PackageManager.isMoveStatusFinished(status)) {
1502 Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status);
1503
1504 mMoveCallback = null;
1505 mMoveTargetUuid = null;
1506 }
1507 }
1508
Jeff Sharkey48877892015-03-18 11:27:19 -07001509 private void enforcePermission(String perm) {
1510 mContext.enforceCallingOrSelfPermission(perm, perm);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001511 }
1512
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001513 /**
1514 * Decide if volume is mountable per device policies.
1515 */
1516 private boolean isMountDisallowed(VolumeInfo vol) {
Philip P. Moltmannec3cbb22016-09-14 13:24:52 -07001517 UserManager userManager = mContext.getSystemService(UserManager.class);
1518
1519 boolean isUsbRestricted = false;
1520 if (vol.disk != null && vol.disk.isUsb()) {
1521 isUsbRestricted = userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER,
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001522 Binder.getCallingUserHandle());
Emily Bernier92aa5a22014-07-07 10:11:48 -04001523 }
Philip P. Moltmannec3cbb22016-09-14 13:24:52 -07001524
1525 boolean isTypeRestricted = false;
Risan05c41e62018-10-29 08:57:43 +09001526 if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE
1527 || vol.type == VolumeInfo.TYPE_STUB) {
Philip P. Moltmannec3cbb22016-09-14 13:24:52 -07001528 isTypeRestricted = userManager
1529 .hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
1530 Binder.getCallingUserHandle());
1531 }
1532
1533 return isUsbRestricted || isTypeRestricted;
Emily Bernier92aa5a22014-07-07 10:11:48 -04001534 }
1535
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001536 private void enforceAdminUser() {
1537 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1538 final int callingUserId = UserHandle.getCallingUserId();
1539 boolean isAdmin;
1540 long token = Binder.clearCallingIdentity();
1541 try {
1542 isAdmin = um.getUserInfo(callingUserId).isAdmin();
1543 } finally {
1544 Binder.restoreCallingIdentity(token);
1545 }
1546 if (!isAdmin) {
1547 throw new SecurityException("Only admin users can adopt sd cards");
1548 }
1549 }
1550
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001551 /**
Sudheer Shanka2250d562016-11-07 15:41:02 -08001552 * Constructs a new StorageManagerService instance
San Mehat207e5382010-02-04 20:46:54 -08001553 *
1554 * @param context Binder context for this service
1555 */
Sudheer Shanka2250d562016-11-07 15:41:02 -08001556 public StorageManagerService(Context context) {
Christopher Tated417d622013-08-19 16:14:25 -07001557 sSelf = this;
1558
Jeff Sharkey342b4bf2018-12-18 11:12:40 -07001559 // Snapshot feature flag used for this boot
1560 SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT, Boolean.toString(
Jeff Sharkey06376802019-02-11 12:20:02 -07001561 SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, true)));
shafik78fcd502019-09-25 13:50:04 +01001562 SystemProperties.set(StorageManager.PROP_FUSE_SNAPSHOT, Boolean.toString(
1563 SystemProperties.getBoolean(StorageManager.PROP_FUSE, false)));
1564
Zim17be6f92019-09-25 14:37:55 +01001565 mIsFuseEnabled = SystemProperties.getBoolean(StorageManager.PROP_FUSE_SNAPSHOT, false);
San Mehat207e5382010-02-04 20:46:54 -08001566 mContext = context;
Jeff Sharkey5d0c55c2019-01-24 14:32:31 -07001567 mResolver = mContext.getContentResolver();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001568 mCallbacks = new Callbacks(FgThread.get().getLooper());
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001569 mLockPatternUtils = new LockPatternUtils(mContext);
San Mehat207e5382010-02-04 20:46:54 -08001570
Dianne Hackbornefa92b22013-05-03 14:11:43 -07001571 HandlerThread hthread = new HandlerThread(TAG);
1572 hthread.start();
Sudheer Shanka2250d562016-11-07 15:41:02 -08001573 mHandler = new StorageManagerServiceHandler(hthread.getLooper());
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001574
Sudheer Shanka2250d562016-11-07 15:41:02 -08001575 // Add OBB Action Handler to StorageManagerService thread.
Dianne Hackborn8d044e82013-04-30 17:24:15 -07001576 mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
Kenny Roota02b8b02010-08-05 16:14:17 -07001577
Zim17be6f92019-09-25 14:37:55 +01001578 mStorageSessionController = new StorageSessionController(mContext, mIsFuseEnabled);
Zim42f1e9f2019-08-15 17:35:00 +01001579
Christopher Tate7265abe2014-11-21 13:54:45 -08001580 // Initialize the last-fstrim tracking if necessary
1581 File dataDir = Environment.getDataDirectory();
1582 File systemDir = new File(dataDir, "system");
1583 mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
1584 if (!mLastMaintenanceFile.exists()) {
1585 // Not setting mLastMaintenance here means that we will force an
1586 // fstrim during reboot following the OTA that installs this code.
1587 try {
1588 (new FileOutputStream(mLastMaintenanceFile)).close();
1589 } catch (IOException e) {
1590 Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
1591 }
1592 } else {
1593 mLastMaintenance = mLastMaintenanceFile.lastModified();
1594 }
1595
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001596 mSettingsFile = new AtomicFile(
Dianne Hackborne17b4452018-01-10 13:15:40 -08001597 new File(Environment.getDataSystemDirectory(), "storage.xml"), "storage-settings");
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001598
1599 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001600 readSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001601 }
1602
Sudheer Shanka2250d562016-11-07 15:41:02 -08001603 LocalServices.addService(StorageManagerInternal.class, mStorageManagerInternal);
Svet Ganov6ee871e2015-07-10 14:29:33 -07001604
Jeff Sharkeybcd262d2015-06-10 09:41:17 -07001605 final IntentFilter userFilter = new IntentFilter();
1606 userFilter.addAction(Intent.ACTION_USER_ADDED);
1607 userFilter.addAction(Intent.ACTION_USER_REMOVED);
1608 mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
1609
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001610 synchronized (mLock) {
1611 addInternalVolumeLocked();
1612 }
Amith Yamasania7892482015-08-07 11:09:05 -07001613
Kenny Root07714d42011-08-17 17:49:28 -07001614 // Add ourself to the Watchdog monitors if enabled.
1615 if (WATCHDOG_ENABLE) {
1616 Watchdog.getInstance().addMonitor(this);
1617 }
San Mehat207e5382010-02-04 20:46:54 -08001618 }
1619
Abhijeet Kaurb9847712019-11-19 16:35:47 +00001620 /**
1621 * Checks if user changed the persistent settings_fuse flag from Settings UI
1622 * and updates PROP_FUSE (reboots if changed).
1623 */
1624 private void updateFusePropFromSettings() {
1625 Boolean settingsFuseFlag = SystemProperties.getBoolean((FeatureFlagUtils.PERSIST_PREFIX
1626 + FeatureFlagUtils.SETTINGS_FUSE_FLAG), false);
1627 Slog.d(TAG, "The value of Settings Fuse Flag is " + settingsFuseFlag);
1628 if (SystemProperties.getBoolean(StorageManager.PROP_FUSE, false) != settingsFuseFlag) {
1629 Slog.d(TAG, "Set persist.sys.fuse to " + settingsFuseFlag);
1630 SystemProperties.set(StorageManager.PROP_FUSE, Boolean.toString(settingsFuseFlag));
1631 // Perform hard reboot to kick policy into place
1632 mContext.getSystemService(PowerManager.class).reboot("Reboot device for FUSE system"
1633 + "property change to take effect");
1634 }
1635 }
1636
Jeff Sharkeycd575992016-03-29 14:12:49 -06001637 private void start() {
peter.zhangb0d11d12019-06-13 16:39:30 +08001638 connectStoraged();
1639 connectVold();
Jeff Sharkeycd575992016-03-29 14:12:49 -06001640 }
1641
peter.zhangb0d11d12019-06-13 16:39:30 +08001642 private void connectStoraged() {
Jin Qian12690d52017-10-13 18:17:04 -07001643 IBinder binder = ServiceManager.getService("storaged");
1644 if (binder != null) {
1645 try {
1646 binder.linkToDeath(new DeathRecipient() {
1647 @Override
1648 public void binderDied() {
1649 Slog.w(TAG, "storaged died; reconnecting");
1650 mStoraged = null;
peter.zhangb0d11d12019-06-13 16:39:30 +08001651 connectStoraged();
Jin Qian12690d52017-10-13 18:17:04 -07001652 }
1653 }, 0);
1654 } catch (RemoteException e) {
1655 binder = null;
1656 }
1657 }
1658
1659 if (binder != null) {
1660 mStoraged = IStoraged.Stub.asInterface(binder);
1661 } else {
1662 Slog.w(TAG, "storaged not found; trying again");
1663 }
1664
peter.zhangb0d11d12019-06-13 16:39:30 +08001665 if (mStoraged == null) {
1666 BackgroundThread.getHandler().postDelayed(() -> {
1667 connectStoraged();
1668 }, DateUtils.SECOND_IN_MILLIS);
1669 } else {
1670 onDaemonConnected();
1671 }
1672 }
1673
1674 private void connectVold() {
1675 IBinder binder = ServiceManager.getService("vold");
Jeff Sharkey1019de92017-09-06 13:47:03 -06001676 if (binder != null) {
1677 try {
1678 binder.linkToDeath(new DeathRecipient() {
1679 @Override
1680 public void binderDied() {
1681 Slog.w(TAG, "vold died; reconnecting");
Jin Qian12690d52017-10-13 18:17:04 -07001682 mVold = null;
peter.zhangb0d11d12019-06-13 16:39:30 +08001683 connectVold();
Jeff Sharkey1019de92017-09-06 13:47:03 -06001684 }
1685 }, 0);
1686 } catch (RemoteException e) {
1687 binder = null;
1688 }
1689 }
1690
1691 if (binder != null) {
1692 mVold = IVold.Stub.asInterface(binder);
Jeff Sharkey8058fe62017-09-13 11:50:33 -06001693 try {
1694 mVold.setListener(mListener);
Jeff Sharkey8058fe62017-09-13 11:50:33 -06001695 } catch (RemoteException e) {
Jin Qian12690d52017-10-13 18:17:04 -07001696 mVold = null;
Jeff Sharkey8058fe62017-09-13 11:50:33 -06001697 Slog.w(TAG, "vold listener rejected; trying again", e);
1698 }
Jeff Sharkey1019de92017-09-06 13:47:03 -06001699 } else {
1700 Slog.w(TAG, "vold not found; trying again");
Jeff Sharkey1019de92017-09-06 13:47:03 -06001701 }
Jeff Sharkey8058fe62017-09-13 11:50:33 -06001702
peter.zhangb0d11d12019-06-13 16:39:30 +08001703 if (mVold == null) {
Jin Qian12690d52017-10-13 18:17:04 -07001704 BackgroundThread.getHandler().postDelayed(() -> {
peter.zhangb0d11d12019-06-13 16:39:30 +08001705 connectVold();
Jin Qian12690d52017-10-13 18:17:04 -07001706 }, DateUtils.SECOND_IN_MILLIS);
1707 } else {
1708 onDaemonConnected();
1709 }
Jeff Sharkey1019de92017-09-06 13:47:03 -06001710 }
1711
Jeff Sharkey11697f52018-12-13 10:14:42 -07001712 private void servicesReady() {
Sudheer Shankaff585072019-01-29 23:19:45 -08001713 mPmInternal = LocalServices.getService(PackageManagerInternal.class);
Sudheer Shankaff585072019-01-29 23:19:45 -08001714
1715 mIPackageManager = IPackageManager.Stub.asInterface(
1716 ServiceManager.getService("package"));
1717 mIAppOpsService = IAppOpsService.Stub.asInterface(
1718 ServiceManager.getService(Context.APP_OPS_SERVICE));
Zim74a9bba2019-09-03 20:49:13 +01001719
1720 ProviderInfo provider = mPmInternal.resolveContentProvider(
1721 MediaStore.AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE
1722 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
1723 UserHandle.getUserId(UserHandle.USER_SYSTEM));
1724 if (provider != null) {
Martijn Coenen44db1ac2019-12-03 16:06:19 +01001725 mMediaStoreAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
Zim74a9bba2019-09-03 20:49:13 +01001726 }
1727
Sudheer Shankaff585072019-01-29 23:19:45 -08001728 try {
1729 mIAppOpsService.startWatchingMode(OP_REQUEST_INSTALL_PACKAGES, null, mAppOpsCallback);
Sudheer Shanka783c90e2019-04-12 13:55:20 -07001730 mIAppOpsService.startWatchingMode(OP_LEGACY_STORAGE, null, mAppOpsCallback);
Sudheer Shankaff585072019-01-29 23:19:45 -08001731 } catch (RemoteException e) {
1732 }
Jeff Sharkey11697f52018-12-13 10:14:42 -07001733 }
1734
1735 private static long getLastAccessTime(AppOpsManager manager,
1736 int uid, String packageName, int[] ops) {
1737 long maxTime = 0;
1738 final List<AppOpsManager.PackageOps> pkgs = manager.getOpsForPackage(uid, packageName, ops);
Eugene Susla04d021c2018-12-17 14:49:59 -08001739 for (AppOpsManager.PackageOps pkg : CollectionUtils.emptyIfNull(pkgs)) {
1740 for (AppOpsManager.OpEntry op : CollectionUtils.emptyIfNull(pkg.getOps())) {
Svet Ganovaf189e32019-02-15 18:45:29 -08001741 maxTime = Math.max(maxTime, op.getLastAccessTime(
1742 AppOpsManager.OP_FLAGS_ALL_TRUSTED));
Jeff Sharkey11697f52018-12-13 10:14:42 -07001743 }
1744 }
1745 return maxTime;
1746 }
1747
Jeff Sharkey56e62932015-03-21 20:41:00 -07001748 private void systemReady() {
Wale Ogunwale6767eae2018-05-03 15:52:51 -07001749 LocalServices.getService(ActivityTaskManagerInternal.class)
Jeff Sharkey9765e442017-12-14 22:15:14 -07001750 .registerScreenObserver(this);
1751
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001752 mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
1753 }
1754
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001755 private void bootCompleted() {
1756 mBootCompleted = true;
Daniel Rosenberg137aed12019-03-15 18:41:11 -07001757 mHandler.obtainMessage(H_BOOT_COMPLETED).sendToTarget();
Abhijeet Kaur10c56552019-12-04 14:17:40 +00001758 updateFusePropFromSettings();
Daniel Rosenberg137aed12019-03-15 18:41:11 -07001759 }
1760
1761 private void handleBootCompleted() {
1762 initIfBootedAndConnected();
1763 resetIfBootedAndConnected();
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001764 }
1765
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001766 private String getDefaultPrimaryStorageUuid() {
1767 if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) {
1768 return StorageManager.UUID_PRIMARY_PHYSICAL;
1769 } else {
1770 return StorageManager.UUID_PRIVATE_INTERNAL;
1771 }
1772 }
1773
Andreas Gampea36dc622018-02-05 17:19:22 -08001774 @GuardedBy("mLock")
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001775 private void readSettingsLocked() {
1776 mRecords.clear();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001777 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001778
1779 FileInputStream fis = null;
1780 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001781 fis = mSettingsFile.openRead();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001782 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001783 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001784
1785 int type;
1786 while ((type = in.next()) != END_DOCUMENT) {
1787 if (type == START_TAG) {
1788 final String tag = in.getName();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001789 if (TAG_VOLUMES.equals(tag)) {
1790 final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001791 final boolean primaryPhysical = SystemProperties.getBoolean(
1792 StorageManager.PROP_PRIMARY_PHYSICAL, false);
1793 final boolean validAttr = (version >= VERSION_FIX_PRIMARY)
1794 || (version >= VERSION_ADD_PRIMARY && !primaryPhysical);
1795 if (validAttr) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001796 mPrimaryStorageUuid = readStringAttribute(in,
1797 ATTR_PRIMARY_STORAGE_UUID);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001798 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001799 } else if (TAG_VOLUME.equals(tag)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001800 final VolumeRecord rec = readVolumeRecord(in);
1801 mRecords.put(rec.fsUuid, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001802 }
1803 }
1804 }
1805 } catch (FileNotFoundException e) {
1806 // Missing metadata is okay, probably first boot
1807 } catch (IOException e) {
1808 Slog.wtf(TAG, "Failed reading metadata", e);
1809 } catch (XmlPullParserException e) {
1810 Slog.wtf(TAG, "Failed reading metadata", e);
1811 } finally {
1812 IoUtils.closeQuietly(fis);
1813 }
1814 }
1815
Andreas Gampea36dc622018-02-05 17:19:22 -08001816 @GuardedBy("mLock")
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001817 private void writeSettingsLocked() {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001818 FileOutputStream fos = null;
1819 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001820 fos = mSettingsFile.startWrite();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001821
1822 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001823 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001824 out.startDocument(null, true);
1825 out.startTag(null, TAG_VOLUMES);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001826 writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001827 writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001828 final int size = mRecords.size();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001829 for (int i = 0; i < size; i++) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001830 final VolumeRecord rec = mRecords.valueAt(i);
1831 writeVolumeRecord(out, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001832 }
1833 out.endTag(null, TAG_VOLUMES);
1834 out.endDocument();
1835
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001836 mSettingsFile.finishWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001837 } catch (IOException e) {
1838 if (fos != null) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001839 mSettingsFile.failWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001840 }
1841 }
1842 }
1843
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001844 public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
1845 final int type = readIntAttribute(in, ATTR_TYPE);
1846 final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
1847 final VolumeRecord meta = new VolumeRecord(type, fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001848 meta.partGuid = readStringAttribute(in, ATTR_PART_GUID);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001849 meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
1850 meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
Jeff Sharkey3811f352019-05-14 11:54:36 -06001851 meta.createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS, 0);
1852 meta.lastSeenMillis = readLongAttribute(in, ATTR_LAST_SEEN_MILLIS, 0);
1853 meta.lastTrimMillis = readLongAttribute(in, ATTR_LAST_TRIM_MILLIS, 0);
1854 meta.lastBenchMillis = readLongAttribute(in, ATTR_LAST_BENCH_MILLIS, 0);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001855 return meta;
1856 }
1857
1858 public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
1859 out.startTag(null, TAG_VOLUME);
1860 writeIntAttribute(out, ATTR_TYPE, rec.type);
1861 writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001862 writeStringAttribute(out, ATTR_PART_GUID, rec.partGuid);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001863 writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
1864 writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001865 writeLongAttribute(out, ATTR_CREATED_MILLIS, rec.createdMillis);
Jeff Sharkey3811f352019-05-14 11:54:36 -06001866 writeLongAttribute(out, ATTR_LAST_SEEN_MILLIS, rec.lastSeenMillis);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001867 writeLongAttribute(out, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
1868 writeLongAttribute(out, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001869 out.endTag(null, TAG_VOLUME);
1870 }
1871
San Mehat207e5382010-02-04 20:46:54 -08001872 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001873 * Exposed API calls below here
1874 */
1875
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001876 @Override
Sudheer Shanka2250d562016-11-07 15:41:02 -08001877 public void registerListener(IStorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001878 mCallbacks.register(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001879 }
1880
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001881 @Override
Sudheer Shanka2250d562016-11-07 15:41:02 -08001882 public void unregisterListener(IStorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001883 mCallbacks.unregister(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001884 }
1885
Jeff Sharkey48877892015-03-18 11:27:19 -07001886 @Override
Sudheer Shanka2250d562016-11-07 15:41:02 -08001887 public void shutdown(final IStorageShutdownObserver observer) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001888 enforcePermission(android.Manifest.permission.SHUTDOWN);
San Mehat4270e1e2010-01-29 05:32:19 -08001889
San Mehata5078592010-03-25 09:36:54 -07001890 Slog.i(TAG, "Shutting down");
Jeff Sharkey48877892015-03-18 11:27:19 -07001891 mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001892 }
1893
Jeff Sharkey48877892015-03-18 11:27:19 -07001894 @Override
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001895 public void mount(String volId) {
1896 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001897
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001898 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001899 if (isMountDisallowed(vol)) {
1900 throw new SecurityException("Mounting " + volId + " restricted by policy");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001901 }
Zim17be6f92019-09-25 14:37:55 +01001902
Sudheer Shanka3f0645b2018-09-18 13:07:59 -07001903 mount(vol);
1904 }
1905
Zim17be6f92019-09-25 14:37:55 +01001906 private void mount(VolumeInfo vol) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001907 try {
Zim17be6f92019-09-25 14:37:55 +01001908 // TODO(b/135341433): Remove paranoid logging when FUSE is stable
1909 Slog.i(TAG, "Mounting volume " + vol);
Zim95eca1d2019-11-15 18:03:00 +00001910 mVold.mount(vol.id, vol.mountFlags, vol.mountUserId, new IVoldMountCallback.Stub() {
1911 @Override
1912 public boolean onVolumeChecking(FileDescriptor deviceFd, String path,
1913 String internalPath) {
1914 vol.path = path;
1915 vol.internalPath = internalPath;
1916 try {
1917 mStorageSessionController.onVolumeMount(deviceFd, vol);
1918 return true;
1919 } catch (ExternalStorageServiceException e) {
1920 Slog.i(TAG, "Failed to mount volume " + vol, e);
1921 return false;
1922 }
1923 }
1924 });
Zim17be6f92019-09-25 14:37:55 +01001925 Slog.i(TAG, "Mounted volume " + vol);
Jeff Sharkeyace874b2017-09-07 15:27:33 -06001926 } catch (Exception e) {
1927 Slog.wtf(TAG, e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001928 }
1929 }
1930
1931 @Override
1932 public void unmount(String volId) {
1933 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001934
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001935 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Sudheer Shanka3f0645b2018-09-18 13:07:59 -07001936 unmount(vol);
1937 }
1938
1939 private void unmount(VolumeInfo vol) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001940 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06001941 mVold.unmount(vol.id);
Zim17be6f92019-09-25 14:37:55 +01001942 mStorageSessionController.onVolumeUnmount(vol);
Jeff Sharkeyace874b2017-09-07 15:27:33 -06001943 } catch (Exception e) {
1944 Slog.wtf(TAG, e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001945 }
1946 }
1947
1948 @Override
1949 public void format(String volId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001950 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
San Mehat5b77dab2010-01-26 13:28:50 -08001951
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001952 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001953 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06001954 mVold.format(vol.id, "auto");
Jeff Sharkeyace874b2017-09-07 15:27:33 -06001955 } catch (Exception e) {
1956 Slog.wtf(TAG, e);
Jeff Sharkey48877892015-03-18 11:27:19 -07001957 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001958 }
1959
1960 @Override
Jeff Sharkey7e19f532017-11-06 13:54:11 -07001961 public void benchmark(String volId, IVoldTaskListener listener) {
Jeff Sharkey9756d752015-05-14 21:07:42 -07001962 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Jeff Sharkey9756d752015-05-14 21:07:42 -07001963
1964 try {
Jeff Sharkeyb302c542017-09-15 12:57:59 -06001965 mVold.benchmark(volId, new IVoldTaskListener.Stub() {
1966 @Override
1967 public void onStatus(int status, PersistableBundle extras) {
Jeff Sharkey7e19f532017-11-06 13:54:11 -07001968 dispatchOnStatus(listener, status, extras);
Jeff Sharkeyb302c542017-09-15 12:57:59 -06001969 }
1970
1971 @Override
1972 public void onFinished(int status, PersistableBundle extras) {
Jeff Sharkey7e19f532017-11-06 13:54:11 -07001973 dispatchOnFinished(listener, status, extras);
Jeff Sharkeyb302c542017-09-15 12:57:59 -06001974
1975 final String path = extras.getString("path");
1976 final String ident = extras.getString("ident");
1977 final long create = extras.getLong("create");
1978 final long run = extras.getLong("run");
1979 final long destroy = extras.getLong("destroy");
1980
1981 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
1982 dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
1983 + " " + ident + " " + create + " " + run + " " + destroy);
1984
1985 synchronized (mLock) {
1986 final VolumeRecord rec = findRecordForPath(path);
1987 if (rec != null) {
1988 rec.lastBenchMillis = System.currentTimeMillis();
1989 writeSettingsLocked();
1990 }
1991 }
1992 }
1993 });
Jeff Sharkey7e19f532017-11-06 13:54:11 -07001994 } catch (RemoteException e) {
1995 throw e.rethrowAsRuntimeException();
Jeff Sharkey9756d752015-05-14 21:07:42 -07001996 }
1997 }
1998
1999 @Override
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07002000 public void partitionPublic(String diskId) {
2001 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07002002
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07002003 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07002004 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002005 mVold.partition(diskId, IVold.PARTITION_TYPE_PUBLIC, -1);
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07002006 waitForLatch(latch, "partitionPublic", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkeyace874b2017-09-07 15:27:33 -06002007 } catch (Exception e) {
2008 Slog.wtf(TAG, e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07002009 }
2010 }
2011
2012 @Override
2013 public void partitionPrivate(String diskId) {
2014 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07002015 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07002016
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07002017 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07002018 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002019 mVold.partition(diskId, IVold.PARTITION_TYPE_PRIVATE, -1);
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07002020 waitForLatch(latch, "partitionPrivate", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkeyace874b2017-09-07 15:27:33 -06002021 } catch (Exception e) {
2022 Slog.wtf(TAG, e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07002023 }
2024 }
2025
2026 @Override
2027 public void partitionMixed(String diskId, int ratio) {
2028 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07002029 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07002030
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07002031 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07002032 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002033 mVold.partition(diskId, IVold.PARTITION_TYPE_MIXED, ratio);
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07002034 waitForLatch(latch, "partitionMixed", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkeyace874b2017-09-07 15:27:33 -06002035 } catch (Exception e) {
2036 Slog.wtf(TAG, e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07002037 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002038 }
2039
Jeff Sharkey48877892015-03-18 11:27:19 -07002040 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07002041 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07002042 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07002043
Jeff Sharkey50a05452015-04-29 11:24:52 -07002044 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07002045 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07002046 final VolumeRecord rec = mRecords.get(fsUuid);
2047 rec.nickname = nickname;
Jeff Sharkey50a05452015-04-29 11:24:52 -07002048 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07002049 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07002050 }
2051 }
2052
2053 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07002054 public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07002055 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07002056
Jeff Sharkey50a05452015-04-29 11:24:52 -07002057 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07002058 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07002059 final VolumeRecord rec = mRecords.get(fsUuid);
2060 rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
Jeff Sharkey50a05452015-04-29 11:24:52 -07002061 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07002062 writeSettingsLocked();
2063 }
2064 }
2065
2066 @Override
2067 public void forgetVolume(String fsUuid) {
2068 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07002069
Jeff Sharkey50a05452015-04-29 11:24:52 -07002070 Preconditions.checkNotNull(fsUuid);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08002071
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07002072 synchronized (mLock) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07002073 final VolumeRecord rec = mRecords.remove(fsUuid);
2074 if (rec != null && !TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkeydb4b6192017-10-24 11:08:50 -06002075 mHandler.obtainMessage(H_PARTITION_FORGET, rec).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07002076 }
2077 mCallbacks.notifyVolumeForgotten(fsUuid);
Jeff Sharkey50a05452015-04-29 11:24:52 -07002078
2079 // If this had been primary storage, revert back to internal and
2080 // reset vold so we bind into new volume into place.
2081 if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002082 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08002083 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07002084 }
2085
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07002086 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07002087 }
2088 }
2089
Jeff Sharkey7d2af542015-05-12 15:27:15 -07002090 @Override
2091 public void forgetAllVolumes() {
2092 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Jeff Sharkey7d2af542015-05-12 15:27:15 -07002093
Jeff Sharkey50a05452015-04-29 11:24:52 -07002094 synchronized (mLock) {
2095 for (int i = 0; i < mRecords.size(); i++) {
2096 final String fsUuid = mRecords.keyAt(i);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07002097 final VolumeRecord rec = mRecords.valueAt(i);
2098 if (!TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkeydb4b6192017-10-24 11:08:50 -06002099 mHandler.obtainMessage(H_PARTITION_FORGET, rec).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07002100 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07002101 mCallbacks.notifyVolumeForgotten(fsUuid);
2102 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07002103 mRecords.clear();
Jeff Sharkey50a05452015-04-29 11:24:52 -07002104
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002105 if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)) {
2106 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
2107 }
2108
2109 writeSettingsLocked();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08002110 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07002111 }
2112 }
2113
Jeff Sharkeydb4b6192017-10-24 11:08:50 -06002114 private void forgetPartition(String partGuid, String fsUuid) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07002115 try {
Jeff Sharkeydb4b6192017-10-24 11:08:50 -06002116 mVold.forgetPartition(partGuid, fsUuid);
Jeff Sharkeyace874b2017-09-07 15:27:33 -06002117 } catch (Exception e) {
2118 Slog.wtf(TAG, e);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07002119 }
2120 }
2121
Jeff Sharkey31d0b702016-11-21 14:16:53 -07002122 @Override
Jeff Sharkey7e19f532017-11-06 13:54:11 -07002123 public void fstrim(int flags, IVoldTaskListener listener) {
Jeff Sharkey31d0b702016-11-21 14:16:53 -07002124 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Jeff Sharkey31d0b702016-11-21 14:16:53 -07002125
2126 try {
Sandeep Patil7d5c4912019-04-15 09:27:30 -07002127 // Block based checkpoint process runs fstrim. So, if checkpoint is in progress
2128 // (first boot after OTA), We skip idle maintenance and make sure the last
2129 // fstrim time is still updated. If file based checkpoints are used, we run
2130 // idle maintenance (GC + fstrim) regardless of checkpoint status.
2131 if (!needsCheckpoint() || !supportsBlockCheckpoint()) {
2132 mVold.fstrim(flags, new IVoldTaskListener.Stub() {
2133 @Override
2134 public void onStatus(int status, PersistableBundle extras) {
2135 dispatchOnStatus(listener, status, extras);
Jeff Sharkey7e19f532017-11-06 13:54:11 -07002136
Sandeep Patil7d5c4912019-04-15 09:27:30 -07002137 // Ignore trim failures
2138 if (status != 0) return;
Jeff Sharkeyb302c542017-09-15 12:57:59 -06002139
Sandeep Patil7d5c4912019-04-15 09:27:30 -07002140 final String path = extras.getString("path");
2141 final long bytes = extras.getLong("bytes");
2142 final long time = extras.getLong("time");
Jeff Sharkeyb302c542017-09-15 12:57:59 -06002143
Sandeep Patil7d5c4912019-04-15 09:27:30 -07002144 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
2145 dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path) + " " + bytes + " " + time);
Jeff Sharkeyb302c542017-09-15 12:57:59 -06002146
Sandeep Patil7d5c4912019-04-15 09:27:30 -07002147 synchronized (mLock) {
2148 final VolumeRecord rec = findRecordForPath(path);
2149 if (rec != null) {
2150 rec.lastTrimMillis = System.currentTimeMillis();
2151 writeSettingsLocked();
2152 }
Jeff Sharkeyb302c542017-09-15 12:57:59 -06002153 }
2154 }
Jeff Sharkeyb302c542017-09-15 12:57:59 -06002155
Sandeep Patil7d5c4912019-04-15 09:27:30 -07002156 @Override
2157 public void onFinished(int status, PersistableBundle extras) {
2158 dispatchOnFinished(listener, status, extras);
Jeff Sharkey7e19f532017-11-06 13:54:11 -07002159
Sandeep Patil7d5c4912019-04-15 09:27:30 -07002160 // TODO: benchmark when desired
2161 }
2162 });
2163 } else {
2164 Slog.i(TAG, "Skipping fstrim - block based checkpoint in progress");
2165 }
Jeff Sharkey7e19f532017-11-06 13:54:11 -07002166 } catch (RemoteException e) {
2167 throw e.rethrowAsRuntimeException();
Jeff Sharkey31d0b702016-11-21 14:16:53 -07002168 }
2169 }
2170
Jin Qiana85b9912017-10-17 15:48:18 -07002171 void runIdleMaint(Runnable callback) {
2172 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
2173
2174 try {
Sandeep Patil7d5c4912019-04-15 09:27:30 -07002175 // Block based checkpoint process runs fstrim. So, if checkpoint is in progress
2176 // (first boot after OTA), We skip idle maintenance and make sure the last
2177 // fstrim time is still updated. If file based checkpoints are used, we run
2178 // idle maintenance (GC + fstrim) regardless of checkpoint status.
2179 if (!needsCheckpoint() || !supportsBlockCheckpoint()) {
2180 mVold.runIdleMaint(new IVoldTaskListener.Stub() {
2181 @Override
2182 public void onStatus(int status, PersistableBundle extras) {
2183 // Not currently used
Jin Qiana85b9912017-10-17 15:48:18 -07002184 }
Sandeep Patil7d5c4912019-04-15 09:27:30 -07002185 @Override
2186 public void onFinished(int status, PersistableBundle extras) {
2187 if (callback != null) {
2188 BackgroundThread.getHandler().post(callback);
2189 }
2190 }
2191 });
2192 } else {
2193 Slog.i(TAG, "Skipping idle maintenance - block based checkpoint in progress");
2194 }
Jin Qiana85b9912017-10-17 15:48:18 -07002195 } catch (Exception e) {
2196 Slog.wtf(TAG, e);
2197 }
2198 }
2199
2200 @Override
2201 public void runIdleMaintenance() {
2202 runIdleMaint(null);
2203 }
2204
2205 void abortIdleMaint(Runnable callback) {
2206 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
2207
2208 try {
2209 mVold.abortIdleMaint(new IVoldTaskListener.Stub() {
2210 @Override
2211 public void onStatus(int status, PersistableBundle extras) {
2212 // Not currently used
2213 }
2214 @Override
2215 public void onFinished(int status, PersistableBundle extras) {
2216 if (callback != null) {
2217 BackgroundThread.getHandler().post(callback);
2218 }
2219 }
2220 });
2221 } catch (Exception e) {
2222 Slog.wtf(TAG, e);
2223 }
2224 }
2225
2226 @Override
2227 public void abortIdleMaintenance() {
2228 abortIdleMaint(null);
2229 }
2230
Svet Ganov6ee871e2015-07-10 14:29:33 -07002231 private void remountUidExternalStorage(int uid, int mode) {
Jeff Sharkey9527b222015-06-24 15:24:48 -07002232 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002233 mVold.remountUid(uid, mode);
Jeff Sharkeyace874b2017-09-07 15:27:33 -06002234 } catch (Exception e) {
2235 Slog.wtf(TAG, e);
Jeff Sharkey9527b222015-06-24 15:24:48 -07002236 }
2237 }
2238
2239 @Override
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002240 public void setDebugFlags(int flags, int mask) {
2241 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002242
Jeff Sharkeyba512352015-11-12 20:17:45 -08002243 if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
Jeff Sharkey00455bf2016-11-04 14:45:24 -06002244 if (!EMULATE_FBE_SUPPORTED) {
2245 throw new IllegalStateException(
2246 "Emulation not supported on this device");
2247 }
Paul Lawrence20be5d62016-02-26 13:51:17 -08002248 if (StorageManager.isFileEncryptedNativeOnly()) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002249 throw new IllegalStateException(
Jeff Sharkey00455bf2016-11-04 14:45:24 -06002250 "Emulation not supported on device with native FBE");
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002251 }
Jeff Sharkey5a785162016-03-21 13:02:06 -06002252 if (mLockPatternUtils.isCredentialRequiredToDecrypt(false)) {
2253 throw new IllegalStateException(
2254 "Emulation requires disabling 'Secure start-up' in Settings > Security");
2255 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002256
Jeff Sharkey1176e512016-02-29 17:01:26 -07002257 final long token = Binder.clearCallingIdentity();
2258 try {
2259 final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
2260 SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002261
Jeff Sharkey1176e512016-02-29 17:01:26 -07002262 // Perform hard reboot to kick policy into place
2263 mContext.getSystemService(PowerManager.class).reboot(null);
2264 } finally {
2265 Binder.restoreCallingIdentity(token);
2266 }
Jeff Sharkeyba512352015-11-12 20:17:45 -08002267 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002268
Jeff Sharkey901c0422018-04-20 13:11:20 -06002269 if ((mask & (StorageManager.DEBUG_ADOPTABLE_FORCE_ON
2270 | StorageManager.DEBUG_ADOPTABLE_FORCE_OFF)) != 0) {
2271 final String value;
2272 if ((flags & StorageManager.DEBUG_ADOPTABLE_FORCE_ON) != 0) {
2273 value = "force_on";
2274 } else if ((flags & StorageManager.DEBUG_ADOPTABLE_FORCE_OFF) != 0) {
2275 value = "force_off";
2276 } else {
2277 value = "";
2278 }
Jeff Sharkeyba512352015-11-12 20:17:45 -08002279
Jeff Sharkey901c0422018-04-20 13:11:20 -06002280 final long token = Binder.clearCallingIdentity();
2281 try {
2282 SystemProperties.set(StorageManager.PROP_ADOPTABLE, value);
2283
2284 // Reset storage to kick new setting into place
Jeff Sharkeyba512352015-11-12 20:17:45 -08002285 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey901c0422018-04-20 13:11:20 -06002286 } finally {
2287 Binder.restoreCallingIdentity(token);
Jeff Sharkeyba512352015-11-12 20:17:45 -08002288 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002289 }
Jeff Sharkey33dd1562016-04-07 11:05:33 -06002290
2291 if ((mask & (StorageManager.DEBUG_SDCARDFS_FORCE_ON
2292 | StorageManager.DEBUG_SDCARDFS_FORCE_OFF)) != 0) {
2293 final String value;
2294 if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_ON) != 0) {
2295 value = "force_on";
2296 } else if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_OFF) != 0) {
2297 value = "force_off";
2298 } else {
2299 value = "";
2300 }
2301
2302 final long token = Binder.clearCallingIdentity();
2303 try {
2304 SystemProperties.set(StorageManager.PROP_SDCARDFS, value);
2305
2306 // Reset storage to kick new setting into place
2307 mHandler.obtainMessage(H_RESET).sendToTarget();
2308 } finally {
2309 Binder.restoreCallingIdentity(token);
2310 }
2311 }
Jeff Sharkeye53e2d92017-03-25 23:14:06 -06002312
2313 if ((mask & StorageManager.DEBUG_VIRTUAL_DISK) != 0) {
2314 final boolean enabled = (flags & StorageManager.DEBUG_VIRTUAL_DISK) != 0;
2315
2316 final long token = Binder.clearCallingIdentity();
2317 try {
2318 SystemProperties.set(StorageManager.PROP_VIRTUAL_DISK, Boolean.toString(enabled));
2319
2320 // Reset storage to kick new setting into place
2321 mHandler.obtainMessage(H_RESET).sendToTarget();
2322 } finally {
2323 Binder.restoreCallingIdentity(token);
2324 }
2325 }
Sudheer Shankabe0febe2018-11-07 18:24:37 -08002326
Jeff Sharkeyb0c363b22018-12-15 11:53:03 -07002327 if ((mask & (StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_ON
2328 | StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_OFF)) != 0) {
2329 final int value;
2330 if ((flags & StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_ON) != 0) {
2331 value = 1;
2332 } else if ((flags & StorageManager.DEBUG_ISOLATED_STORAGE_FORCE_OFF) != 0) {
2333 value = -1;
2334 } else {
2335 value = 0;
2336 }
Sudheer Shankabe0febe2018-11-07 18:24:37 -08002337
2338 final long token = Binder.clearCallingIdentity();
2339 try {
Jeff Sharkeyb0c363b22018-12-15 11:53:03 -07002340 Settings.Global.putInt(mContext.getContentResolver(),
2341 Settings.Global.ISOLATED_STORAGE_LOCAL, value);
2342 refreshIsolatedStorageSettings();
Sudheer Shankabe0febe2018-11-07 18:24:37 -08002343
2344 // Perform hard reboot to kick policy into place
Jeff Sharkey36274992019-02-27 12:09:57 -07002345 mHandler.post(() -> {
2346 mContext.getSystemService(PowerManager.class).reboot(null);
2347 });
2348 } finally {
2349 Binder.restoreCallingIdentity(token);
2350 }
2351 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002352 }
2353
2354 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002355 public String getPrimaryStorageUuid() {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002356 synchronized (mLock) {
2357 return mPrimaryStorageUuid;
2358 }
2359 }
2360
2361 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002362 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
2363 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002364
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002365 final VolumeInfo from;
2366 final VolumeInfo to;
2367
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002368 synchronized (mLock) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002369 if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) {
2370 throw new IllegalArgumentException("Primary storage already at " + volumeUuid);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002371 }
2372
2373 if (mMoveCallback != null) {
2374 throw new IllegalStateException("Move already in progress");
2375 }
2376 mMoveCallback = callback;
2377 mMoveTargetUuid = volumeUuid;
2378
Jeff Sharkeya65e6492017-06-21 13:45:11 -06002379 // We need all the users unlocked to move their primary storage
2380 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
2381 for (UserInfo user : users) {
2382 if (StorageManager.isFileEncryptedNativeOrEmulated()
2383 && !isUserKeyUnlocked(user.id)) {
2384 Slog.w(TAG, "Failing move due to locked user " + user.id);
2385 onMoveStatusLocked(PackageManager.MOVE_FAILED_LOCKED_USER);
2386 return;
2387 }
2388 }
2389
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002390 // When moving to/from primary physical volume, we probably just nuked
2391 // the current storage location, so we have nothing to move.
2392 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
2393 || Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
2394 Slog.d(TAG, "Skipping move to/from primary physical");
2395 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
2396 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08002397 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002398 return;
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002399
2400 } else {
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002401 from = findStorageForUuid(mPrimaryStorageUuid);
2402 to = findStorageForUuid(volumeUuid);
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07002403
2404 if (from == null) {
2405 Slog.w(TAG, "Failing move due to missing from volume " + mPrimaryStorageUuid);
2406 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2407 return;
2408 } else if (to == null) {
2409 Slog.w(TAG, "Failing move due to missing to volume " + volumeUuid);
2410 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2411 return;
2412 }
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002413 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002414 }
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002415
2416 try {
Jeff Sharkeyb302c542017-09-15 12:57:59 -06002417 mVold.moveStorage(from.id, to.id, new IVoldTaskListener.Stub() {
2418 @Override
2419 public void onStatus(int status, PersistableBundle extras) {
2420 synchronized (mLock) {
2421 onMoveStatusLocked(status);
2422 }
2423 }
2424
2425 @Override
2426 public void onFinished(int status, PersistableBundle extras) {
2427 // Not currently used
2428 }
2429 });
Jeff Sharkeyace874b2017-09-07 15:27:33 -06002430 } catch (Exception e) {
2431 Slog.wtf(TAG, e);
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002432 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002433 }
2434
San Mehatb1043402010-02-05 08:26:50 -08002435 private void warnOnNotMounted() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002436 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002437 for (int i = 0; i < mVolumes.size(); i++) {
2438 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07002439 if (vol.isPrimary() && vol.isMountedWritable()) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002440 // Cool beans, we have a mounted primary volume
2441 return;
2442 }
Jeff Sharkey32ee8312012-09-30 13:21:31 -07002443 }
San Mehatb1043402010-02-05 08:26:50 -08002444 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002445
2446 Slog.w(TAG, "No primary storage mounted!");
San Mehatb1043402010-02-05 08:26:50 -08002447 }
2448
Kenny Roota02b8b02010-08-05 16:14:17 -07002449 private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
2450 if (callerUid == android.os.Process.SYSTEM_UID) {
2451 return true;
2452 }
2453
Kenny Root02c87302010-07-01 08:10:18 -07002454 if (packageName == null) {
2455 return false;
2456 }
2457
Jeff Sharkey5790af02018-08-13 17:42:54 -06002458 final int packageUid = mPmInternal.getPackageUid(packageName,
Jeff Sharkeycd654482016-01-08 17:42:11 -07002459 PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callerUid));
Kenny Root02c87302010-07-01 08:10:18 -07002460
2461 if (DEBUG_OBB) {
2462 Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
2463 packageUid + ", callerUid = " + callerUid);
2464 }
2465
2466 return callerUid == packageUid;
2467 }
2468
Jeff Sharkey54402792017-09-15 16:05:19 -06002469 @Override
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002470 public String getMountedObbPath(String rawPath) {
2471 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002472
Kenny Root02c87302010-07-01 08:10:18 -07002473 warnOnNotMounted();
2474
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002475 final ObbState state;
Rubin Xucd7a0142015-04-17 23:45:27 +01002476 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002477 state = mObbPathToStateMap.get(rawPath);
2478 }
2479 if (state == null) {
2480 Slog.w(TAG, "Failed to find OBB mounted at " + rawPath);
2481 return null;
2482 }
2483
Jeff Sharkey54402792017-09-15 16:05:19 -06002484 return findVolumeByIdOrThrow(state.volId).getPath().getAbsolutePath();
Kenny Root02c87302010-07-01 08:10:18 -07002485 }
2486
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002487 @Override
2488 public boolean isObbMounted(String rawPath) {
2489 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002490 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002491 return mObbPathToStateMap.containsKey(rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002492 }
Kenny Root02c87302010-07-01 08:10:18 -07002493 }
2494
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002495 @Override
Sudheer Shanka25469aa2018-08-27 15:50:23 -07002496 public void mountObb(String rawPath, String canonicalPath, String key,
2497 IObbActionListener token, int nonce, ObbInfo obbInfo) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002498 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2499 Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
2500 Preconditions.checkNotNull(token, "token cannot be null");
Sudheer Shanka25469aa2018-08-27 15:50:23 -07002501 Preconditions.checkNotNull(obbInfo, "obbIfno cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002502
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002503 final int callingUid = Binder.getCallingUid();
Jeff Sharkey41cd6812017-09-11 10:32:17 -06002504 final ObbState obbState = new ObbState(rawPath, canonicalPath,
2505 callingUid, token, nonce, null);
Sudheer Shanka25469aa2018-08-27 15:50:23 -07002506 final ObbAction action = new MountObbAction(obbState, key, callingUid, obbInfo);
Kenny Roota02b8b02010-08-05 16:14:17 -07002507 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
2508
2509 if (DEBUG_OBB)
2510 Slog.i(TAG, "Send to OBB handler: " + action.toString());
Kenny Root02c87302010-07-01 08:10:18 -07002511 }
2512
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002513 @Override
2514 public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
2515 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2516
2517 final ObbState existingState;
Rubin Xucd7a0142015-04-17 23:45:27 +01002518 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002519 existingState = mObbPathToStateMap.get(rawPath);
Kenny Rootf1121dc2010-09-29 07:30:53 -07002520 }
2521
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002522 if (existingState != null) {
2523 // TODO: separate state object from request data
2524 final int callingUid = Binder.getCallingUid();
Jeff Sharkey41cd6812017-09-11 10:32:17 -06002525 final ObbState newState = new ObbState(rawPath, existingState.canonicalPath,
2526 callingUid, token, nonce, existingState.volId);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002527 final ObbAction action = new UnmountObbAction(newState, force);
2528 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root02c87302010-07-01 08:10:18 -07002529
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002530 if (DEBUG_OBB)
2531 Slog.i(TAG, "Send to OBB handler: " + action.toString());
2532 } else {
2533 Slog.w(TAG, "Unknown OBB mount at " + rawPath);
2534 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002535 }
2536
Ben Komalo444eca22011-09-01 15:17:44 -07002537 @Override
2538 public int getEncryptionState() {
2539 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2540 "no permission to access the crypt keeper");
2541
Ben Komalo444eca22011-09-01 15:17:44 -07002542 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002543 return mVold.fdeComplete();
2544 } catch (Exception e) {
2545 Slog.wtf(TAG, e);
Sudheer Shankaf7341142016-10-18 17:15:18 -07002546 return StorageManager.ENCRYPTION_STATE_ERROR_UNKNOWN;
Ben Komalo444eca22011-09-01 15:17:44 -07002547 }
2548 }
2549
2550 @Override
Jason parks5af0b912010-11-29 09:05:25 -06002551 public int decryptStorage(String password) {
Jason parks8888c592011-01-20 22:46:41 -06002552 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2553 "no permission to access the crypt keeper");
Jason parks5af0b912010-11-29 09:05:25 -06002554
Jeff Sharkey8058fe62017-09-13 11:50:33 -06002555 if (TextUtils.isEmpty(password)) {
2556 throw new IllegalArgumentException("password cannot be empty");
2557 }
2558
Jason parks5af0b912010-11-29 09:05:25 -06002559 if (DEBUG_EVENTS) {
2560 Slog.i(TAG, "decrypting storage...");
2561 }
2562
2563 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002564 mVold.fdeCheckPassword(password);
2565 mHandler.postDelayed(() -> {
2566 try {
2567 mVold.fdeRestart();
2568 } catch (Exception e) {
2569 Slog.wtf(TAG, e);
2570 }
2571 }, DateUtils.SECOND_IN_MILLIS);
2572 return 0;
Paul Crowleyfc0b5192018-07-02 13:58:10 -07002573 } catch (ServiceSpecificException e) {
2574 Slog.e(TAG, "fdeCheckPassword failed", e);
2575 return e.errorCode;
Jeff Sharkey54402792017-09-15 16:05:19 -06002576 } catch (Exception e) {
2577 Slog.wtf(TAG, e);
2578 return StorageManager.ENCRYPTION_STATE_ERROR_UNKNOWN;
Jason parks5af0b912010-11-29 09:05:25 -06002579 }
Jason parks5af0b912010-11-29 09:05:25 -06002580 }
2581
Jeff Sharkey54402792017-09-15 16:05:19 -06002582 @Override
Paul Lawrence46791e72014-04-03 09:10:26 -07002583 public int encryptStorage(int type, String password) {
Jason parks8888c592011-01-20 22:46:41 -06002584 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2585 "no permission to access the crypt keeper");
Jason parks56aa5322011-01-07 09:01:15 -06002586
Jeff Sharkey8058fe62017-09-13 11:50:33 -06002587 if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
2588 password = "";
2589 } else if (TextUtils.isEmpty(password)) {
2590 throw new IllegalArgumentException("password cannot be empty");
2591 }
2592
Jason parks56aa5322011-01-07 09:01:15 -06002593 if (DEBUG_EVENTS) {
Jason parks8888c592011-01-20 22:46:41 -06002594 Slog.i(TAG, "encrypting storage...");
Jason parks56aa5322011-01-07 09:01:15 -06002595 }
2596
2597 try {
Paul Lawrence89a0ae42017-12-22 10:11:10 -08002598 mVold.fdeEnable(type, password, 0);
Jeff Sharkey43e12112017-09-12 16:31:45 -06002599 } catch (Exception e) {
2600 Slog.wtf(TAG, e);
2601 return -1;
Jason parks56aa5322011-01-07 09:01:15 -06002602 }
2603
2604 return 0;
2605 }
2606
Paul Lawrence8e397362014-01-27 15:22:30 -08002607 /** Set the password for encrypting the master key.
2608 * @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
2609 * @param password The password to set.
2610 */
Jeff Sharkey54402792017-09-15 16:05:19 -06002611 @Override
Paul Lawrence8e397362014-01-27 15:22:30 -08002612 public int changeEncryptionPassword(int type, String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002613 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2614 "no permission to access the crypt keeper");
2615
Jeff Sharkeyae266462017-11-27 13:32:24 -07002616 if (StorageManager.isFileEncryptedNativeOnly()) {
2617 // Not supported on FBE devices
2618 return -1;
2619 }
2620
Jeff Sharkey8058fe62017-09-13 11:50:33 -06002621 if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
2622 password = "";
2623 } else if (TextUtils.isEmpty(password)) {
2624 throw new IllegalArgumentException("password cannot be empty");
2625 }
2626
Jason parksf7b3cd42011-01-27 09:28:25 -06002627 if (DEBUG_EVENTS) {
2628 Slog.i(TAG, "changing encryption password...");
2629 }
2630
2631 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002632 mVold.fdeChangePassword(type, password);
2633 return 0;
2634 } catch (Exception e) {
2635 Slog.wtf(TAG, e);
2636 return -1;
Jason parksf7b3cd42011-01-27 09:28:25 -06002637 }
2638 }
2639
Christopher Tate32418be2011-10-10 13:51:12 -07002640 /**
2641 * Validate a user-supplied password string with cryptfs
2642 */
2643 @Override
2644 public int verifyEncryptionPassword(String password) throws RemoteException {
2645 // Only the system process is permitted to validate passwords
2646 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2647 throw new SecurityException("no permission to access the crypt keeper");
2648 }
2649
2650 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2651 "no permission to access the crypt keeper");
2652
2653 if (TextUtils.isEmpty(password)) {
2654 throw new IllegalArgumentException("password cannot be empty");
2655 }
2656
Christopher Tate32418be2011-10-10 13:51:12 -07002657 if (DEBUG_EVENTS) {
2658 Slog.i(TAG, "validating encryption password...");
2659 }
2660
2661 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002662 mVold.fdeVerifyPassword(password);
2663 return 0;
2664 } catch (Exception e) {
2665 Slog.wtf(TAG, e);
2666 return -1;
Christopher Tate32418be2011-10-10 13:51:12 -07002667 }
2668 }
2669
Paul Lawrence8e397362014-01-27 15:22:30 -08002670 /**
2671 * Get the type of encryption used to encrypt the master key.
2672 * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
2673 */
2674 @Override
Svetoslav16e4a1a2014-09-29 18:16:20 -07002675 public int getPasswordType() {
Paul Lawrence76a40572017-03-15 11:08:04 -07002676 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Paul Lawrence9de713d2016-05-02 22:45:33 +00002677 "no permission to access the crypt keeper");
2678
Paul Lawrence8e397362014-01-27 15:22:30 -08002679 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002680 return mVold.fdeGetPasswordType();
2681 } catch (Exception e) {
2682 Slog.wtf(TAG, e);
2683 return -1;
Paul Lawrence8e397362014-01-27 15:22:30 -08002684 }
2685 }
2686
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002687 /**
2688 * Set a field in the crypto header.
2689 * @param field field to set
2690 * @param contents contents to set in field
2691 */
2692 @Override
2693 public void setField(String field, String contents) throws RemoteException {
Paul Lawrence76a40572017-03-15 11:08:04 -07002694 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002695 "no permission to access the crypt keeper");
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002696
yusukes14a8b1f2018-07-23 17:34:42 -07002697 if (!StorageManager.isBlockEncrypted()) {
2698 // Only supported on FDE devices
Jeff Sharkeyae266462017-11-27 13:32:24 -07002699 return;
2700 }
2701
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002702 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002703 mVold.fdeSetField(field, contents);
2704 return;
2705 } catch (Exception e) {
2706 Slog.wtf(TAG, e);
2707 return;
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002708 }
2709 }
2710
2711 /**
2712 * Gets a field from the crypto header.
2713 * @param field field to get
2714 * @return contents of field
2715 */
2716 @Override
2717 public String getField(String field) throws RemoteException {
Paul Lawrence76a40572017-03-15 11:08:04 -07002718 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002719 "no permission to access the crypt keeper");
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002720
yusukes14a8b1f2018-07-23 17:34:42 -07002721 if (!StorageManager.isBlockEncrypted()) {
2722 // Only supported on FDE devices
Jeff Sharkeyae266462017-11-27 13:32:24 -07002723 return null;
2724 }
2725
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002726 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002727 return mVold.fdeGetField(field);
2728 } catch (Exception e) {
2729 Slog.wtf(TAG, e);
2730 return null;
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002731 }
2732 }
2733
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002734 /**
2735 * Is userdata convertible to file based encryption?
2736 * @return non zero for convertible
2737 */
2738 @Override
2739 public boolean isConvertibleToFBE() throws RemoteException {
Paul Lawrence76a40572017-03-15 11:08:04 -07002740 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002741 "no permission to access the crypt keeper");
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002742
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002743 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002744 return mVold.isConvertibleToFbe();
2745 } catch (Exception e) {
2746 Slog.wtf(TAG, e);
2747 return false;
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002748 }
2749 }
2750
Daniel Rosenberge129e5c2018-11-07 19:25:55 -08002751 /**
Martijn Coenenf04aca42019-03-11 10:35:34 +01002752 * Check whether the device supports filesystem checkpointing.
2753 *
2754 * @return true if the device supports filesystem checkpointing, false otherwise.
2755 */
2756 @Override
2757 public boolean supportsCheckpoint() throws RemoteException {
Martijn Coenenf04aca42019-03-11 10:35:34 +01002758 return mVold.supportsCheckpoint();
2759 }
2760
2761 /**
2762 * Signal that checkpointing partitions should start a checkpoint on the next boot.
2763 *
2764 * @param numTries Number of times to try booting in checkpoint mode, before we will boot
2765 * non-checkpoint mode and commit all changes immediately. Callers are
2766 * responsible for ensuring that boot is safe (eg, by rolling back updates).
2767 */
2768 @Override
2769 public void startCheckpoint(int numTries) throws RemoteException {
2770 // Only the system process is permitted to start checkpoints
2771 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2772 throw new SecurityException("no permission to start filesystem checkpoint");
2773 }
2774
2775 mVold.startCheckpoint(numTries);
2776 }
2777
2778 /**
Daniel Rosenberge129e5c2018-11-07 19:25:55 -08002779 * Signal that checkpointing partitions should commit changes
2780 */
2781 @Override
2782 public void commitChanges() throws RemoteException {
2783 // Only the system process is permitted to commit checkpoints
2784 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2785 throw new SecurityException("no permission to commit checkpoint changes");
2786 }
2787
2788 mVold.commitChanges();
2789 }
2790
Daniel Rosenberge3a924d2019-03-19 18:19:08 -07002791 /**
2792 * Check if we should be mounting with checkpointing or are checkpointing now
2793 */
2794 @Override
2795 public boolean needsCheckpoint() throws RemoteException {
Paul Lawrence15a54462019-04-30 11:14:25 -07002796 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Daniel Rosenberge3a924d2019-03-19 18:19:08 -07002797 return mVold.needsCheckpoint();
2798 }
2799
Daniel Rosenberg600799b2019-03-20 17:42:50 -07002800 /**
2801 * Abort the current set of changes and either try again, or abort entirely
2802 */
2803 @Override
2804 public void abortChanges(String message, boolean retry) throws RemoteException {
2805 // Only the system process is permitted to abort checkpoints
2806 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2807 throw new SecurityException("no permission to commit checkpoint changes");
2808 }
2809
2810 mVold.abortChanges(message, retry);
2811 }
2812
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002813 @Override
Paul Lawrence945490c2014-03-27 16:37:28 +00002814 public String getPassword() throws RemoteException {
Paul Lawrence76a40572017-03-15 11:08:04 -07002815 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Rubin Xucd7a0142015-04-17 23:45:27 +01002816 "only keyguard can retrieve password");
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002817
Paul Lawrence945490c2014-03-27 16:37:28 +00002818 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002819 return mVold.fdeGetPassword();
2820 } catch (Exception e) {
2821 Slog.wtf(TAG, e);
Paul Lawrence24063b52015-01-06 13:11:23 -08002822 return null;
Paul Lawrence945490c2014-03-27 16:37:28 +00002823 }
2824 }
2825
2826 @Override
2827 public void clearPassword() throws RemoteException {
Paul Lawrence76a40572017-03-15 11:08:04 -07002828 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002829 "only keyguard can clear password");
2830
Paul Lawrence945490c2014-03-27 16:37:28 +00002831 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002832 mVold.fdeClearPassword();
2833 return;
2834 } catch (Exception e) {
2835 Slog.wtf(TAG, e);
2836 return;
Paul Lawrence945490c2014-03-27 16:37:28 +00002837 }
2838 }
2839
2840 @Override
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002841 public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002842 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002843
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002844 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002845 mVold.createUserKey(userId, serialNumber, ephemeral);
Jeff Sharkey43e12112017-09-12 16:31:45 -06002846 } catch (Exception e) {
2847 Slog.wtf(TAG, e);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002848 }
2849 }
2850
Paul Crowley7ec733f2015-05-19 12:42:00 +01002851 @Override
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002852 public void destroyUserKey(int userId) {
2853 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowley7ec733f2015-05-19 12:42:00 +01002854
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002855 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002856 mVold.destroyUserKey(userId);
Jeff Sharkey43e12112017-09-12 16:31:45 -06002857 } catch (Exception e) {
2858 Slog.wtf(TAG, e);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002859 }
2860 }
2861
Jeff Sharkey43e12112017-09-12 16:31:45 -06002862 private String encodeBytes(byte[] bytes) {
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002863 if (ArrayUtils.isEmpty(bytes)) {
Jeff Sharkey43e12112017-09-12 16:31:45 -06002864 return "!";
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002865 } else {
Jeff Sharkey43e12112017-09-12 16:31:45 -06002866 return HexDump.toHexString(bytes);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002867 }
2868 }
2869
Paul Crowleycc701552016-05-17 14:18:49 -07002870 /*
2871 * Add this token/secret pair to the set of ways we can recover a disk encryption key.
2872 * Changing the token/secret for a disk encryption key is done in two phases: first, adding
2873 * a new token/secret pair with this call, then delting all other pairs with
2874 * fixateNewestUserKeyAuth. This allows other places where a credential is used, such as
2875 * Gatekeeper, to be updated between the two calls.
2876 */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002877 @Override
Paul Crowleycc701552016-05-17 14:18:49 -07002878 public void addUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002879 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002880
2881 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002882 mVold.addUserKeyAuth(userId, serialNumber, encodeBytes(token), encodeBytes(secret));
Jeff Sharkey43e12112017-09-12 16:31:45 -06002883 } catch (Exception e) {
2884 Slog.wtf(TAG, e);
Paul Crowleycc701552016-05-17 14:18:49 -07002885 }
2886 }
2887
2888 /*
2889 * Delete all disk encryption token/secret pairs except the most recently added one
2890 */
2891 @Override
2892 public void fixateNewestUserKeyAuth(int userId) {
2893 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowleycc701552016-05-17 14:18:49 -07002894
2895 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002896 mVold.fixateNewestUserKeyAuth(userId);
Jeff Sharkey43e12112017-09-12 16:31:45 -06002897 } catch (Exception e) {
2898 Slog.wtf(TAG, e);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002899 }
2900 }
2901
2902 @Override
2903 public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
Sudheer Shanka03b20ec2019-02-21 15:11:00 -08002904 Slog.d(TAG, "unlockUserKey: " + userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002905 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002906
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002907 if (StorageManager.isFileEncryptedNativeOrEmulated()) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002908 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002909 mVold.unlockUserKey(userId, serialNumber, encodeBytes(token),
2910 encodeBytes(secret));
Jeff Sharkey43e12112017-09-12 16:31:45 -06002911 } catch (Exception e) {
2912 Slog.wtf(TAG, e);
2913 return;
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002914 }
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002915 }
2916
2917 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002918 mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002919 }
2920 }
2921
2922 @Override
2923 public void lockUserKey(int userId) {
2924 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002925
2926 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002927 mVold.lockUserKey(userId);
Jeff Sharkey43e12112017-09-12 16:31:45 -06002928 } catch (Exception e) {
2929 Slog.wtf(TAG, e);
2930 return;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002931 }
2932
2933 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002934 mLocalUnlockedUsers = ArrayUtils.removeInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002935 }
2936 }
2937
2938 @Override
2939 public boolean isUserKeyUnlocked(int userId) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002940 synchronized (mLock) {
2941 return ArrayUtils.contains(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002942 }
2943 }
2944
Narayan Kamath157dd1d2019-06-12 13:06:30 +01002945 private boolean isSystemUnlocked(int userId) {
2946 synchronized (mLock) {
2947 return ArrayUtils.contains(mSystemUnlockedUsers, userId);
2948 }
2949 }
2950
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002951 @Override
Jeff Sharkey47f71082016-02-01 17:03:54 -07002952 public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002953 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002954
2955 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002956 mVold.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
Jeff Sharkey43e12112017-09-12 16:31:45 -06002957 } catch (Exception e) {
2958 Slog.wtf(TAG, e);
Paul Crowley7ec733f2015-05-19 12:42:00 +01002959 }
2960 }
2961
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002962 @Override
Jeff Sharkeyfcf1e552016-04-14 20:44:58 -06002963 public void destroyUserStorage(String volumeUuid, int userId, int flags) {
2964 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Jeff Sharkeyfcf1e552016-04-14 20:44:58 -06002965
2966 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06002967 mVold.destroyUserStorage(volumeUuid, userId, flags);
Jeff Sharkey43e12112017-09-12 16:31:45 -06002968 } catch (Exception e) {
2969 Slog.wtf(TAG, e);
Jeff Sharkeyfcf1e552016-04-14 20:44:58 -06002970 }
2971 }
2972
Anton Hanssonbe9c9902019-05-28 13:45:26 +01002973 /** Not thread safe */
Daichi Hironoe56740d2017-02-02 13:56:45 +09002974 class AppFuseMountScope extends AppFuseBridge.MountScope {
Anton Hanssonbe9c9902019-05-28 13:45:26 +01002975 private boolean mMounted = false;
Daichi Hirono812c95d2017-02-08 16:20:20 +09002976
Ryo Hashimoto38bcbf02018-05-16 18:20:37 +09002977 public AppFuseMountScope(int uid, int mountId) {
2978 super(uid, mountId);
Daichi Hirono812c95d2017-02-08 16:20:20 +09002979 }
2980
2981 @Override
2982 public ParcelFileDescriptor open() throws NativeDaemonConnectorException {
Jeff Sharkey54402792017-09-15 16:05:19 -06002983 try {
Anton Hanssonbe9c9902019-05-28 13:45:26 +01002984 final FileDescriptor fd = mVold.mountAppFuse(uid, mountId);
2985 mMounted = true;
2986 return new ParcelFileDescriptor(fd);
Jeff Sharkey54402792017-09-15 16:05:19 -06002987 } catch (Exception e) {
2988 throw new NativeDaemonConnectorException("Failed to mount", e);
Daichi Hirono812c95d2017-02-08 16:20:20 +09002989 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09002990 }
2991
2992 @Override
Ryo Hashimoto38bcbf02018-05-16 18:20:37 +09002993 public ParcelFileDescriptor openFile(int mountId, int fileId, int flags)
2994 throws NativeDaemonConnectorException {
2995 try {
2996 return new ParcelFileDescriptor(
2997 mVold.openAppFuseFile(uid, mountId, fileId, flags));
2998 } catch (Exception e) {
2999 throw new NativeDaemonConnectorException("Failed to open", e);
3000 }
3001 }
3002
3003 @Override
Daichi Hironoe56740d2017-02-02 13:56:45 +09003004 public void close() throws Exception {
Anton Hanssonbe9c9902019-05-28 13:45:26 +01003005 if (mMounted) {
Ryo Hashimoto38bcbf02018-05-16 18:20:37 +09003006 mVold.unmountAppFuse(uid, mountId);
Anton Hanssonbe9c9902019-05-28 13:45:26 +01003007 mMounted = false;
Daichi Hirono812c95d2017-02-08 16:20:20 +09003008 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09003009 }
3010 }
3011
3012 @Override
Daichi Hirono812c95d2017-02-08 16:20:20 +09003013 public @Nullable AppFuseMount mountProxyFileDescriptorBridge() {
Daichi Hironoe56740d2017-02-02 13:56:45 +09003014 Slog.v(TAG, "mountProxyFileDescriptorBridge");
Daichi Hirono9fb00182016-11-08 14:12:17 +09003015 final int uid = Binder.getCallingUid();
Daichi Hirono9fb00182016-11-08 14:12:17 +09003016
Daichi Hironoe56740d2017-02-02 13:56:45 +09003017 while (true) {
3018 synchronized (mAppFuseLock) {
3019 boolean newlyCreated = false;
3020 if (mAppFuseBridge == null) {
3021 mAppFuseBridge = new AppFuseBridge();
3022 new Thread(mAppFuseBridge, AppFuseBridge.TAG).start();
3023 newlyCreated = true;
Daichi Hirono9fb00182016-11-08 14:12:17 +09003024 }
Daichi Hironoe56740d2017-02-02 13:56:45 +09003025 try {
3026 final int name = mNextAppFuseName++;
3027 try {
3028 return new AppFuseMount(
Ryo Hashimoto38bcbf02018-05-16 18:20:37 +09003029 name, mAppFuseBridge.addBridge(new AppFuseMountScope(uid, name)));
Daichi Hirono812c95d2017-02-08 16:20:20 +09003030 } catch (FuseUnavailableMountException e) {
Daichi Hironoe56740d2017-02-02 13:56:45 +09003031 if (newlyCreated) {
3032 // If newly created bridge fails, it's a real error.
Daichi Hirono812c95d2017-02-08 16:20:20 +09003033 Slog.e(TAG, "", e);
3034 return null;
Daichi Hironoe56740d2017-02-02 13:56:45 +09003035 }
3036 // It seems the thread of mAppFuseBridge has already been terminated.
3037 mAppFuseBridge = null;
3038 }
3039 } catch (NativeDaemonConnectorException e) {
3040 throw e.rethrowAsParcelableException();
3041 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09003042 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09003043 }
3044 }
3045
3046 @Override
Daichi Hirono812c95d2017-02-08 16:20:20 +09003047 public @Nullable ParcelFileDescriptor openProxyFileDescriptor(
3048 int mountId, int fileId, int mode) {
3049 Slog.v(TAG, "mountProxyFileDescriptor");
Jeff Sharkey39466322018-12-05 19:19:52 -07003050
3051 // We only support a narrow set of incoming mode flags
Jeff Sharkey3b1c2542018-12-13 15:01:38 -07003052 mode &= MODE_READ_WRITE;
Jeff Sharkey39466322018-12-05 19:19:52 -07003053
Daichi Hirono9fb00182016-11-08 14:12:17 +09003054 try {
3055 synchronized (mAppFuseLock) {
Daichi Hironoe56740d2017-02-02 13:56:45 +09003056 if (mAppFuseBridge == null) {
Daichi Hirono812c95d2017-02-08 16:20:20 +09003057 Slog.e(TAG, "FuseBridge has not been created");
3058 return null;
Daichi Hirono9fb00182016-11-08 14:12:17 +09003059 }
Ryo Hashimoto38bcbf02018-05-16 18:20:37 +09003060 return mAppFuseBridge.openFile(mountId, fileId, mode);
Daichi Hirono9fb00182016-11-08 14:12:17 +09003061 }
Daichi Hirono812c95d2017-02-08 16:20:20 +09003062 } catch (FuseUnavailableMountException | InterruptedException error) {
3063 Slog.v(TAG, "The mount point has already been invalid", error);
3064 return null;
Daichi Hirono9fb00182016-11-08 14:12:17 +09003065 }
3066 }
3067
Daichi Hirono9e8d9e22015-11-13 14:37:00 +09003068 @Override
Jeff Sharkeyae266462017-11-27 13:32:24 -07003069 public void mkdirs(String callingPkg, String appPath) {
Zim17be6f92019-09-25 14:37:55 +01003070 if (mIsFuseEnabled) {
3071 // TODO(b/144332951): Calling into Vold is risky because the FUSE daemon can go down
3072 // anytime and Vold will hang forever. We should either remove this call
3073 // or at least call into the FUSE daemon to mkdir instead
3074 Slog.w(TAG, "Not making dir for package " + callingPkg + " with path " + appPath);
3075 return;
3076 }
3077
Sudheer Shankaa63bfb32019-02-28 11:15:58 -08003078 final int callingUid = Binder.getCallingUid();
3079 final int userId = UserHandle.getUserId(callingUid);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003080 final UserEnvironment userEnv = new UserEnvironment(userId);
Farid Zare Seisanac094512018-04-02 15:06:13 -07003081 final String propertyName = "sys.user." + userId + ".ce_available";
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003082
Jeff Sharkey196c7552018-03-26 15:56:50 -06003083 // Ignore requests to create directories while storage is locked
Farid Zare Seisanac094512018-04-02 15:06:13 -07003084 if (!isUserKeyUnlocked(userId)) {
3085 throw new IllegalStateException("Failed to prepare " + appPath);
3086 }
3087
3088 // Ignore requests to create directories if CE storage is not available
Farid Zare Seisan7f6b8122018-03-30 11:19:10 -07003089 if ((userId == UserHandle.USER_SYSTEM)
3090 && !SystemProperties.getBoolean(propertyName, false)) {
Farid Zare Seisanac094512018-04-02 15:06:13 -07003091 throw new IllegalStateException("Failed to prepare " + appPath);
3092 }
Jeff Sharkey196c7552018-03-26 15:56:50 -06003093
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003094 // Validate that reported package name belongs to caller
3095 final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
3096 Context.APP_OPS_SERVICE);
Sudheer Shankaa63bfb32019-02-28 11:15:58 -08003097 appOps.checkPackage(callingUid, callingPkg);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003098
Jeff Sharkey48877892015-03-18 11:27:19 -07003099 File appFile = null;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003100 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07003101 appFile = new File(appPath).getCanonicalFile();
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003102 } catch (IOException e) {
Jeff Sharkeyae266462017-11-27 13:32:24 -07003103 throw new IllegalStateException("Failed to resolve " + appPath + ": " + e);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003104 }
3105
3106 // Try translating the app path into a vold path, but require that it
3107 // belong to the calling package.
Jeff Sharkey48877892015-03-18 11:27:19 -07003108 if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) ||
3109 FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) ||
3110 FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) {
3111 appPath = appFile.getAbsolutePath();
3112 if (!appPath.endsWith("/")) {
3113 appPath = appPath + "/";
3114 }
3115
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003116 try {
Sudheer Shanka64501e52019-04-29 10:46:26 -07003117 mVold.mkdirs(appPath);
Jeff Sharkey27a108c2017-11-30 17:11:40 -07003118 return;
Jeff Sharkeyace874b2017-09-07 15:27:33 -06003119 } catch (Exception e) {
Sudheer Shanka64501e52019-04-29 10:46:26 -07003120 throw new IllegalStateException("Failed to prepare " + appPath + ": " + e);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003121 }
3122 }
3123
Jeff Sharkey48877892015-03-18 11:27:19 -07003124 throw new SecurityException("Invalid mkdirs path: " + appFile);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003125 }
3126
3127 @Override
Jeff Sharkey46349872015-07-28 10:49:47 -07003128 public StorageVolume[] getVolumeList(int uid, String packageName, int flags) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003129 final int userId = UserHandle.getUserId(uid);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003130
Jeff Sharkey46349872015-07-28 10:49:47 -07003131 final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0;
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003132 final boolean realState = (flags & StorageManager.FLAG_REAL_STATE) != 0;
3133 final boolean includeInvisible = (flags & StorageManager.FLAG_INCLUDE_INVISIBLE) != 0;
Jeff Sharkey46349872015-07-28 10:49:47 -07003134
Narayan Kamath157dd1d2019-06-12 13:06:30 +01003135 // Report all volumes as unmounted until we've recorded that user 0 has unlocked. There
3136 // are no guarantees that callers will see a consistent view of the volume before that
3137 // point
3138 final boolean systemUserUnlocked = isSystemUnlocked(UserHandle.USER_SYSTEM);
3139
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003140 final boolean userKeyUnlocked;
3141 final boolean storagePermission;
3142 final long token = Binder.clearCallingIdentity();
Svetoslav38c3dbb2015-07-14 11:27:06 -07003143 try {
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003144 userKeyUnlocked = isUserKeyUnlocked(userId);
Sudheer Shanka2250d562016-11-07 15:41:02 -08003145 storagePermission = mStorageManagerInternal.hasExternalStorage(uid, packageName);
Svetoslav38c3dbb2015-07-14 11:27:06 -07003146 } finally {
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003147 Binder.restoreCallingIdentity(token);
Svetoslav38c3dbb2015-07-14 11:27:06 -07003148 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003149
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003150 boolean foundPrimary = false;
3151
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003152 final ArrayList<StorageVolume> res = new ArrayList<>();
Jeff Sharkey48877892015-03-18 11:27:19 -07003153 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003154 for (int i = 0; i < mVolumes.size(); i++) {
3155 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003156 switch (vol.getType()) {
3157 case VolumeInfo.TYPE_PUBLIC:
Risan05c41e62018-10-29 08:57:43 +09003158 case VolumeInfo.TYPE_STUB:
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003159 break;
Zim17be6f92019-09-25 14:37:55 +01003160 case VolumeInfo.TYPE_EMULATED:
3161 if (vol.getMountUserId() == userId) {
3162 break;
3163 }
3164 // Skip if emulated volume not for userId
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003165 default:
3166 continue;
3167 }
3168
3169 boolean match = false;
3170 if (forWrite) {
3171 match = vol.isVisibleForWrite(userId);
3172 } else {
Felipe Leme123a0e72016-06-10 11:09:11 -07003173 match = vol.isVisibleForRead(userId)
3174 || (includeInvisible && vol.getPath() != null);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003175 }
3176 if (!match) continue;
3177
3178 boolean reportUnmounted = false;
Narayan Kamath157dd1d2019-06-12 13:06:30 +01003179 if (!systemUserUnlocked) {
3180 reportUnmounted = true;
3181 } else if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !userKeyUnlocked) {
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003182 reportUnmounted = true;
3183 } else if (!storagePermission && !realState) {
3184 reportUnmounted = true;
3185 }
3186
3187 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
3188 reportUnmounted);
3189 if (vol.isPrimary()) {
3190 res.add(0, userVol);
3191 foundPrimary = true;
3192 } else {
3193 res.add(userVol);
Jeff Sharkeyb049e212012-09-07 23:16:01 -07003194 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003195 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003196 }
Jeff Sharkey48877892015-03-18 11:27:19 -07003197
3198 if (!foundPrimary) {
Jeff Sharkey11697f52018-12-13 10:14:42 -07003199 Slog.w(TAG, "No primary storage defined yet; hacking together a stub");
Jeff Sharkey48877892015-03-18 11:27:19 -07003200
3201 final boolean primaryPhysical = SystemProperties.getBoolean(
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003202 StorageManager.PROP_PRIMARY_PHYSICAL, false);
Jeff Sharkey48877892015-03-18 11:27:19 -07003203
3204 final String id = "stub_primary";
3205 final File path = Environment.getLegacyExternalStorageDirectory();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003206 final String description = mContext.getString(android.R.string.unknownName);
Jeff Sharkey48877892015-03-18 11:27:19 -07003207 final boolean primary = true;
3208 final boolean removable = primaryPhysical;
3209 final boolean emulated = !primaryPhysical;
Jeff Sharkey48877892015-03-18 11:27:19 -07003210 final boolean allowMassStorage = false;
3211 final long maxFileSize = 0L;
3212 final UserHandle owner = new UserHandle(userId);
3213 final String uuid = null;
Jeff Sharkey48877892015-03-18 11:27:19 -07003214 final String state = Environment.MEDIA_REMOVED;
3215
Jerry Zhang71938e12018-05-10 18:28:29 -07003216 res.add(0, new StorageVolume(id, path, path,
Jerry Zhangf9c5c252017-08-16 18:07:51 -07003217 description, primary, removable, emulated,
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003218 allowMassStorage, maxFileSize, owner, uuid, state));
Jeff Sharkey48877892015-03-18 11:27:19 -07003219 }
3220
3221 return res.toArray(new StorageVolume[res.size()]);
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003222 }
3223
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003224 @Override
3225 public DiskInfo[] getDisks() {
3226 synchronized (mLock) {
3227 final DiskInfo[] res = new DiskInfo[mDisks.size()];
3228 for (int i = 0; i < mDisks.size(); i++) {
3229 res[i] = mDisks.valueAt(i);
3230 }
3231 return res;
3232 }
3233 }
3234
3235 @Override
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003236 public VolumeInfo[] getVolumes(int flags) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003237 synchronized (mLock) {
3238 final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
3239 for (int i = 0; i < mVolumes.size(); i++) {
3240 res[i] = mVolumes.valueAt(i);
3241 }
3242 return res;
3243 }
3244 }
3245
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003246 @Override
3247 public VolumeRecord[] getVolumeRecords(int flags) {
3248 synchronized (mLock) {
3249 final VolumeRecord[] res = new VolumeRecord[mRecords.size()];
3250 for (int i = 0; i < mRecords.size(); i++) {
3251 res[i] = mRecords.valueAt(i);
3252 }
3253 return res;
3254 }
3255 }
3256
Jeff Sharkey9bed0702017-01-23 20:37:05 -07003257 @Override
3258 public long getCacheQuotaBytes(String volumeUuid, int uid) {
3259 if (uid != Binder.getCallingUid()) {
3260 mContext.enforceCallingPermission(android.Manifest.permission.STORAGE_INTERNAL, TAG);
3261 }
Daniel Nishi80fdb012017-03-09 14:30:07 -08003262 final long token = Binder.clearCallingIdentity();
3263 final StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class);
3264 try {
3265 return stats.getCacheQuotaBytes(volumeUuid, uid);
3266 } finally {
3267 Binder.restoreCallingIdentity(token);
3268 }
Jeff Sharkey9bed0702017-01-23 20:37:05 -07003269 }
3270
3271 @Override
3272 public long getCacheSizeBytes(String volumeUuid, int uid) {
3273 if (uid != Binder.getCallingUid()) {
3274 mContext.enforceCallingPermission(android.Manifest.permission.STORAGE_INTERNAL, TAG);
3275 }
3276 final long token = Binder.clearCallingIdentity();
3277 try {
3278 return mContext.getSystemService(StorageStatsManager.class)
3279 .queryStatsForUid(volumeUuid, uid).getCacheBytes();
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06003280 } catch (IOException e) {
3281 throw new ParcelableException(e);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07003282 } finally {
3283 Binder.restoreCallingIdentity(token);
3284 }
3285 }
3286
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003287 private int adjustAllocateFlags(int flags, int callingUid, String callingPackage) {
3288 // Require permission to allocate aggressively
3289 if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003290 mContext.enforceCallingOrSelfPermission(
3291 android.Manifest.permission.ALLOCATE_AGGRESSIVE, TAG);
3292 }
3293
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003294 // Apps normally can't directly defy reserved space
3295 flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED;
3296 flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED;
3297
3298 // However, if app is actively using the camera, then we're willing to
3299 // clear up to half of the reserved cache space, since the user might be
3300 // trying to capture an important memory.
3301 final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
3302 final long token = Binder.clearCallingIdentity();
3303 try {
3304 if (appOps.isOperationActive(AppOpsManager.OP_CAMERA, callingUid, callingPackage)) {
3305 Slog.d(TAG, "UID " + callingUid + " is actively using camera;"
3306 + " letting them defy reserved cached data");
3307 flags |= StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED;
3308 }
3309 } finally {
3310 Binder.restoreCallingIdentity(token);
3311 }
3312
3313 return flags;
3314 }
3315
3316 @Override
3317 public long getAllocatableBytes(String volumeUuid, int flags, String callingPackage) {
3318 flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage);
3319
3320 final StorageManager storage = mContext.getSystemService(StorageManager.class);
3321 final StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003322 final long token = Binder.clearCallingIdentity();
3323 try {
3324 // In general, apps can allocate as much space as they want, except
3325 // we never let them eat into either the minimum cache space or into
Jeff Sharkeyddff8072017-05-26 13:10:46 -06003326 // the low disk warning space. To avoid user confusion, this logic
3327 // should be kept in sync with getFreeBytes().
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003328 final File path = storage.findPathForUuid(volumeUuid);
Jeff Sharkeyddff8072017-05-26 13:10:46 -06003329
Noah Zimmtb2558072019-07-25 16:15:06 -07003330 long usable = 0;
3331 long lowReserved = 0;
3332 long fullReserved = 0;
3333 long cacheClearable = 0;
Jeff Sharkeyddff8072017-05-26 13:10:46 -06003334
Noah Zimmtb2558072019-07-25 16:15:06 -07003335 if ((flags & StorageManager.FLAG_ALLOCATE_CACHE_ONLY) == 0) {
3336 usable = path.getUsableSpace();
3337 lowReserved = storage.getStorageLowBytes(path);
3338 fullReserved = storage.getStorageFullBytes(path);
3339 }
3340
3341 if ((flags & StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY) == 0
3342 && stats.isQuotaSupported(volumeUuid)) {
Jeff Sharkeyddff8072017-05-26 13:10:46 -06003343 final long cacheTotal = stats.getCacheBytes(volumeUuid);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003344 final long cacheReserved = storage.getStorageCacheBytes(path, flags);
Noah Zimmtb2558072019-07-25 16:15:06 -07003345 cacheClearable = Math.max(0, cacheTotal - cacheReserved);
3346 }
Jeff Sharkeyddff8072017-05-26 13:10:46 -06003347
Noah Zimmtb2558072019-07-25 16:15:06 -07003348 if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
3349 return Math.max(0, (usable + cacheClearable) - fullReserved);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003350 } else {
Noah Zimmtb2558072019-07-25 16:15:06 -07003351 return Math.max(0, (usable + cacheClearable) - lowReserved);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003352 }
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06003353 } catch (IOException e) {
3354 throw new ParcelableException(e);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003355 } finally {
3356 Binder.restoreCallingIdentity(token);
3357 }
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07003358 }
3359
3360 @Override
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003361 public void allocateBytes(String volumeUuid, long bytes, int flags, String callingPackage) {
3362 flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003363
Noah Zimmtb2558072019-07-25 16:15:06 -07003364 final long allocatableBytes = getAllocatableBytes(volumeUuid,
3365 flags | StorageManager.FLAG_ALLOCATE_NON_CACHE_ONLY, callingPackage);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003366 if (bytes > allocatableBytes) {
Noah Zimmtb2558072019-07-25 16:15:06 -07003367 // If we don't have room without taking cache into account, check to see if we'd have
3368 // room if we included freeable cache space.
3369 final long cacheClearable = getAllocatableBytes(volumeUuid,
3370 flags | StorageManager.FLAG_ALLOCATE_CACHE_ONLY, callingPackage);
3371 if (bytes > allocatableBytes + cacheClearable) {
3372 throw new ParcelableException(new IOException("Failed to allocate " + bytes
3373 + " because only " + (allocatableBytes + cacheClearable) + " allocatable"));
3374 }
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003375 }
3376
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003377 final StorageManager storage = mContext.getSystemService(StorageManager.class);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003378 final long token = Binder.clearCallingIdentity();
3379 try {
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06003380 // Free up enough disk space to satisfy both the requested allocation
3381 // and our low disk warning space.
3382 final File path = storage.findPathForUuid(volumeUuid);
Jeff Sharkeyddff8072017-05-26 13:10:46 -06003383 if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
3384 bytes += storage.getStorageFullBytes(path);
3385 } else {
3386 bytes += storage.getStorageLowBytes(path);
3387 }
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06003388
Jeff Sharkey5790af02018-08-13 17:42:54 -06003389 mPmInternal.freeStorage(volumeUuid, bytes, flags);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003390 } catch (IOException e) {
3391 throw new ParcelableException(e);
3392 } finally {
3393 Binder.restoreCallingIdentity(token);
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07003394 }
3395 }
3396
Sudheer Shankaff971bc2018-12-13 17:39:59 -08003397 private IAppOpsCallback.Stub mAppOpsCallback = new IAppOpsCallback.Stub() {
3398 @Override
3399 public void opChanged(int op, int uid, String packageName) throws RemoteException {
3400 if (!ENABLE_ISOLATED_STORAGE) return;
3401
Sudheer Shankaacbba9e2019-05-24 11:23:36 -07003402 remountUidExternalStorage(uid, getMountMode(uid, packageName));
Sudheer Shankaff971bc2018-12-13 17:39:59 -08003403 }
3404 };
3405
Kenny Rootaf9d6672010-10-08 09:21:39 -07003406 private void addObbStateLocked(ObbState obbState) throws RemoteException {
3407 final IBinder binder = obbState.getBinder();
3408 List<ObbState> obbStates = mObbMounts.get(binder);
Kenny Root5919ac62010-10-05 09:49:40 -07003409
Kenny Rootaf9d6672010-10-08 09:21:39 -07003410 if (obbStates == null) {
3411 obbStates = new ArrayList<ObbState>();
3412 mObbMounts.put(binder, obbStates);
3413 } else {
3414 for (final ObbState o : obbStates) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003415 if (o.rawPath.equals(obbState.rawPath)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003416 throw new IllegalStateException("Attempt to add ObbState twice. "
Sudheer Shanka2250d562016-11-07 15:41:02 -08003417 + "This indicates an error in the StorageManagerService logic.");
Kenny Root5919ac62010-10-05 09:49:40 -07003418 }
3419 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003420 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003421
3422 obbStates.add(obbState);
3423 try {
3424 obbState.link();
3425 } catch (RemoteException e) {
3426 /*
3427 * The binder died before we could link it, so clean up our state
3428 * and return failure.
3429 */
3430 obbStates.remove(obbState);
3431 if (obbStates.isEmpty()) {
3432 mObbMounts.remove(binder);
3433 }
3434
3435 // Rethrow the error so mountObb can get it
3436 throw e;
3437 }
3438
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003439 mObbPathToStateMap.put(obbState.rawPath, obbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003440 }
3441
Kenny Rootaf9d6672010-10-08 09:21:39 -07003442 private void removeObbStateLocked(ObbState obbState) {
3443 final IBinder binder = obbState.getBinder();
3444 final List<ObbState> obbStates = mObbMounts.get(binder);
3445 if (obbStates != null) {
3446 if (obbStates.remove(obbState)) {
3447 obbState.unlink();
Kenny Root05105f72010-09-22 17:29:43 -07003448 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003449 if (obbStates.isEmpty()) {
3450 mObbMounts.remove(binder);
3451 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003452 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003453
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003454 mObbPathToStateMap.remove(obbState.rawPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003455 }
3456
Kenny Roota02b8b02010-08-05 16:14:17 -07003457 private class ObbActionHandler extends Handler {
Kenny Roota02b8b02010-08-05 16:14:17 -07003458
3459 ObbActionHandler(Looper l) {
3460 super(l);
3461 }
3462
3463 @Override
3464 public void handleMessage(Message msg) {
3465 switch (msg.what) {
3466 case OBB_RUN_ACTION: {
Kenny Root480afe72010-10-07 10:17:50 -07003467 final ObbAction action = (ObbAction) msg.obj;
Kenny Roota02b8b02010-08-05 16:14:17 -07003468
3469 if (DEBUG_OBB)
3470 Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
3471
Sudheer Shanka25469aa2018-08-27 15:50:23 -07003472 action.execute(this);
Kenny Roota02b8b02010-08-05 16:14:17 -07003473 break;
3474 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003475 case OBB_FLUSH_MOUNT_STATE: {
3476 final String path = (String) msg.obj;
3477
3478 if (DEBUG_OBB)
3479 Slog.i(TAG, "Flushing all OBB state for path " + path);
3480
3481 synchronized (mObbMounts) {
3482 final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
3483
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003484 final Iterator<ObbState> i = mObbPathToStateMap.values().iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003485 while (i.hasNext()) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003486 final ObbState state = i.next();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003487
3488 /*
3489 * If this entry's source file is in the volume path
3490 * that got unmounted, remove it because it's no
3491 * longer valid.
3492 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003493 if (state.canonicalPath.startsWith(path)) {
3494 obbStatesToRemove.add(state);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003495 }
3496 }
3497
3498 for (final ObbState obbState : obbStatesToRemove) {
3499 if (DEBUG_OBB)
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003500 Slog.i(TAG, "Removing state for " + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003501
3502 removeObbStateLocked(obbState);
3503
3504 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003505 obbState.token.onObbResult(obbState.rawPath, obbState.nonce,
Kenny Rootaf9d6672010-10-08 09:21:39 -07003506 OnObbStateChangeListener.UNMOUNTED);
3507 } catch (RemoteException e) {
3508 Slog.i(TAG, "Couldn't send unmount notification for OBB: "
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003509 + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003510 }
3511 }
3512 }
3513 break;
3514 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003515 }
3516 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003517 }
3518
Jeff Sharkey0095a822018-02-15 13:06:53 -07003519 private static class ObbException extends Exception {
3520 public final int status;
3521
3522 public ObbException(int status, String message) {
3523 super(message);
3524 this.status = status;
3525 }
3526
3527 public ObbException(int status, Throwable cause) {
3528 super(cause.getMessage(), cause);
3529 this.status = status;
3530 }
3531 }
3532
Kenny Roota02b8b02010-08-05 16:14:17 -07003533 abstract class ObbAction {
Kenny Roota02b8b02010-08-05 16:14:17 -07003534
3535 ObbState mObbState;
3536
3537 ObbAction(ObbState obbState) {
3538 mObbState = obbState;
3539 }
3540
3541 public void execute(ObbActionHandler handler) {
3542 try {
3543 if (DEBUG_OBB)
Ben Komalo444eca22011-09-01 15:17:44 -07003544 Slog.i(TAG, "Starting to execute action: " + toString());
Sudheer Shanka25469aa2018-08-27 15:50:23 -07003545 handleExecute();
Jeff Sharkey0095a822018-02-15 13:06:53 -07003546 } catch (ObbException e) {
3547 notifyObbStateChange(e);
Kenny Roota02b8b02010-08-05 16:14:17 -07003548 }
3549 }
3550
Jeff Sharkey0095a822018-02-15 13:06:53 -07003551 abstract void handleExecute() throws ObbException;
Kenny Root38cf8862010-09-26 14:18:51 -07003552
Jeff Sharkey0095a822018-02-15 13:06:53 -07003553 protected void notifyObbStateChange(ObbException e) {
3554 Slog.w(TAG, e);
3555 notifyObbStateChange(e.status);
3556 }
3557
3558 protected void notifyObbStateChange(int status) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003559 if (mObbState == null || mObbState.token == null) {
3560 return;
3561 }
3562
Kenny Root38cf8862010-09-26 14:18:51 -07003563 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003564 mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
Kenny Root38cf8862010-09-26 14:18:51 -07003565 } catch (RemoteException e) {
Sudheer Shanka2250d562016-11-07 15:41:02 -08003566 Slog.w(TAG, "StorageEventListener went away while calling onObbStateChanged");
Kenny Root38cf8862010-09-26 14:18:51 -07003567 }
3568 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003569 }
3570
3571 class MountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003572 private final String mKey;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003573 private final int mCallingUid;
Sudheer Shanka25469aa2018-08-27 15:50:23 -07003574 private ObbInfo mObbInfo;
Kenny Roota02b8b02010-08-05 16:14:17 -07003575
Sudheer Shanka25469aa2018-08-27 15:50:23 -07003576 MountObbAction(ObbState obbState, String key, int callingUid, ObbInfo obbInfo) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003577 super(obbState);
3578 mKey = key;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003579 mCallingUid = callingUid;
Sudheer Shanka25469aa2018-08-27 15:50:23 -07003580 mObbInfo = obbInfo;
Kenny Roota02b8b02010-08-05 16:14:17 -07003581 }
3582
Jason parks5af0b912010-11-29 09:05:25 -06003583 @Override
Jeff Sharkey0095a822018-02-15 13:06:53 -07003584 public void handleExecute() throws ObbException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003585 warnOnNotMounted();
3586
Sudheer Shanka25469aa2018-08-27 15:50:23 -07003587 if (!isUidOwnerOfPackageOrSystem(mObbInfo.packageName, mCallingUid)) {
Jeff Sharkey0095a822018-02-15 13:06:53 -07003588 throw new ObbException(ERROR_PERMISSION_DENIED, "Denied attempt to mount OBB "
Sudheer Shanka25469aa2018-08-27 15:50:23 -07003589 + mObbInfo.filename + " which is owned by " + mObbInfo.packageName);
Kenny Roota02b8b02010-08-05 16:14:17 -07003590 }
3591
Kenny Rootaf9d6672010-10-08 09:21:39 -07003592 final boolean isMounted;
3593 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003594 isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003595 }
3596 if (isMounted) {
Jeff Sharkey0095a822018-02-15 13:06:53 -07003597 throw new ObbException(ERROR_ALREADY_MOUNTED,
Sudheer Shanka25469aa2018-08-27 15:50:23 -07003598 "Attempt to mount OBB which is already mounted: " + mObbInfo.filename);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003599 }
3600
Kenny Rootaf9d6672010-10-08 09:21:39 -07003601 final String hashedKey;
Jeff Sharkey41cd6812017-09-11 10:32:17 -06003602 final String binderKey;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003603 if (mKey == null) {
3604 hashedKey = "none";
Jeff Sharkey41cd6812017-09-11 10:32:17 -06003605 binderKey = "";
Kenny Rootaf9d6672010-10-08 09:21:39 -07003606 } else {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003607 try {
Kenny Root3b1abba2010-10-13 15:00:07 -07003608 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
3609
Sudheer Shanka25469aa2018-08-27 15:50:23 -07003610 KeySpec ks = new PBEKeySpec(mKey.toCharArray(), mObbInfo.salt,
Kenny Root3b1abba2010-10-13 15:00:07 -07003611 PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
3612 SecretKey key = factory.generateSecret(ks);
3613 BigInteger bi = new BigInteger(key.getEncoded());
3614 hashedKey = bi.toString(16);
Jeff Sharkey41cd6812017-09-11 10:32:17 -06003615 binderKey = hashedKey;
Jeff Sharkey0095a822018-02-15 13:06:53 -07003616 } catch (GeneralSecurityException e) {
3617 throw new ObbException(ERROR_INTERNAL, e);
Kenny Root38cf8862010-09-26 14:18:51 -07003618 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003619 }
Kenny Root38cf8862010-09-26 14:18:51 -07003620
Kenny Rootaf9d6672010-10-08 09:21:39 -07003621 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06003622 mObbState.volId = mVold.createObb(mObbState.canonicalPath, binderKey,
3623 mObbState.ownerGid);
Zim95eca1d2019-11-15 18:03:00 +00003624 mVold.mount(mObbState.volId, 0, -1, null);
Kenny Roota02b8b02010-08-05 16:14:17 -07003625
Kenny Rootaf9d6672010-10-08 09:21:39 -07003626 if (DEBUG_OBB)
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003627 Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003628
3629 synchronized (mObbMounts) {
3630 addObbStateLocked(mObbState);
3631 }
3632
Jeff Sharkey0095a822018-02-15 13:06:53 -07003633 notifyObbStateChange(MOUNTED);
3634 } catch (Exception e) {
3635 throw new ObbException(ERROR_COULD_NOT_MOUNT, e);
Kenny Root02c87302010-07-01 08:10:18 -07003636 }
3637 }
3638
Jason parks5af0b912010-11-29 09:05:25 -06003639 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003640 public String toString() {
3641 StringBuilder sb = new StringBuilder();
3642 sb.append("MountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003643 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003644 sb.append('}');
3645 return sb.toString();
3646 }
3647 }
3648
3649 class UnmountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003650 private final boolean mForceUnmount;
Kenny Roota02b8b02010-08-05 16:14:17 -07003651
3652 UnmountObbAction(ObbState obbState, boolean force) {
3653 super(obbState);
3654 mForceUnmount = force;
3655 }
3656
Jason parks5af0b912010-11-29 09:05:25 -06003657 @Override
Jeff Sharkey0095a822018-02-15 13:06:53 -07003658 public void handleExecute() throws ObbException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003659 warnOnNotMounted();
3660
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003661 final ObbState existingState;
Kenny Root38cf8862010-09-26 14:18:51 -07003662 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003663 existingState = mObbPathToStateMap.get(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003664 }
Kenny Root38cf8862010-09-26 14:18:51 -07003665
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003666 if (existingState == null) {
Jeff Sharkey0095a822018-02-15 13:06:53 -07003667 throw new ObbException(ERROR_NOT_MOUNTED, "Missing existingState");
Kenny Rootaf9d6672010-10-08 09:21:39 -07003668 }
3669
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003670 if (existingState.ownerGid != mObbState.ownerGid) {
Jeff Sharkey0095a822018-02-15 13:06:53 -07003671 notifyObbStateChange(new ObbException(ERROR_PERMISSION_DENIED,
3672 "Permission denied to unmount OBB " + existingState.rawPath
3673 + " (owned by GID " + existingState.ownerGid + ")"));
Kenny Rootaf9d6672010-10-08 09:21:39 -07003674 return;
3675 }
3676
Kenny Rootaf9d6672010-10-08 09:21:39 -07003677 try {
Jeff Sharkey54402792017-09-15 16:05:19 -06003678 mVold.unmount(mObbState.volId);
3679 mVold.destroyObb(mObbState.volId);
3680 mObbState.volId = null;
Kenny Roota02b8b02010-08-05 16:14:17 -07003681
Kenny Rootaf9d6672010-10-08 09:21:39 -07003682 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003683 removeObbStateLocked(existingState);
Kenny Root38cf8862010-09-26 14:18:51 -07003684 }
3685
Jeff Sharkey0095a822018-02-15 13:06:53 -07003686 notifyObbStateChange(UNMOUNTED);
3687 } catch (Exception e) {
3688 throw new ObbException(ERROR_COULD_NOT_UNMOUNT, e);
Kenny Roota02b8b02010-08-05 16:14:17 -07003689 }
3690 }
3691
Jason parks5af0b912010-11-29 09:05:25 -06003692 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003693 public String toString() {
3694 StringBuilder sb = new StringBuilder();
3695 sb.append("UnmountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003696 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003697 sb.append(",force=");
3698 sb.append(mForceUnmount);
Kenny Roota02b8b02010-08-05 16:14:17 -07003699 sb.append('}');
3700 return sb.toString();
3701 }
Kenny Root02c87302010-07-01 08:10:18 -07003702 }
Kenny Root38cf8862010-09-26 14:18:51 -07003703
Jeff Sharkey7e19f532017-11-06 13:54:11 -07003704 private void dispatchOnStatus(IVoldTaskListener listener, int status,
3705 PersistableBundle extras) {
3706 if (listener != null) {
3707 try {
3708 listener.onStatus(status, extras);
3709 } catch (RemoteException ignored) {
3710 }
3711 }
3712 }
3713
3714 private void dispatchOnFinished(IVoldTaskListener listener, int status,
3715 PersistableBundle extras) {
3716 if (listener != null) {
3717 try {
3718 listener.onFinished(status, extras);
3719 } catch (RemoteException ignored) {
3720 }
3721 }
3722 }
3723
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -08003724 private int getMountMode(int uid, String packageName) {
Jeff Sharkey6fd69942019-03-26 17:53:35 -06003725 final int mode = getMountModeInternal(uid, packageName);
3726 if (LOCAL_LOGV) {
3727 Slog.v(TAG, "Resolved mode " + mode + " for " + packageName + "/"
3728 + UserHandle.formatUid(uid));
3729 }
3730 return mode;
3731 }
3732
3733 private int getMountModeInternal(int uid, String packageName) {
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -08003734 try {
Jeff Sharkey6fd69942019-03-26 17:53:35 -06003735 // Get some easy cases out of the way first
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -08003736 if (Process.isIsolated(uid)) {
3737 return Zygote.MOUNT_EXTERNAL_NONE;
3738 }
Sudheer Shankab1613982019-05-16 16:55:50 -07003739
3740 final String[] packagesForUid = mIPackageManager.getPackagesForUid(uid);
Sudheer Shanka1df72db2019-05-24 10:59:52 -07003741 if (ArrayUtils.isEmpty(packagesForUid)) {
3742 // It's possible the package got uninstalled already, so just ignore.
3743 return Zygote.MOUNT_EXTERNAL_NONE;
3744 }
Sudheer Shankab1613982019-05-16 16:55:50 -07003745 if (packageName == null) {
3746 packageName = packagesForUid[0];
3747 }
3748
Jeff Sharkey6fd69942019-03-26 17:53:35 -06003749 if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) {
Winson Chiu5118d492019-05-15 18:24:06 +00003750 return Zygote.MOUNT_EXTERNAL_NONE;
Jeff Sharkey6fd69942019-03-26 17:53:35 -06003751 }
3752
Martijn Coenen44db1ac2019-12-03 16:06:19 +01003753 if (mIsFuseEnabled && mMediaStoreAuthorityAppId == UserHandle.getAppId(uid)) {
3754 // Determine if caller requires pass_through mount; note that we do this for
3755 // all processes that share a UID with MediaProvider; but this is fine, since
3756 // those processes anyway share the same rights as MediaProvider.
Zim74a9bba2019-09-03 20:49:13 +01003757 return Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
3758 }
3759
Jeff Sharkey6fd69942019-03-26 17:53:35 -06003760 // Determine if caller is holding runtime permission
Chad Brubaker45810af2019-04-08 19:19:48 -07003761 final boolean hasRead = StorageManager.checkPermissionAndCheckOp(mContext, false, 0,
Jeff Sharkey6fd69942019-03-26 17:53:35 -06003762 uid, packageName, READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE);
Chad Brubaker45810af2019-04-08 19:19:48 -07003763 final boolean hasWrite = StorageManager.checkPermissionAndCheckOp(mContext, false, 0,
Jeff Sharkey6fd69942019-03-26 17:53:35 -06003764 uid, packageName, WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE);
Jeff Sharkey6fd69942019-03-26 17:53:35 -06003765
3766 // We're only willing to give out broad access if they also hold
3767 // runtime permission; this is a firm CDD requirement
3768 final boolean hasFull = mIPackageManager.checkUidPermission(WRITE_MEDIA_STORAGE,
3769 uid) == PERMISSION_GRANTED;
Jeff Sharkey26874a22019-04-17 21:30:47 -06003770 if (hasFull && hasWrite) {
Jeff Sharkey6fd69942019-03-26 17:53:35 -06003771 return Zygote.MOUNT_EXTERNAL_FULL;
3772 }
3773
3774 // We're only willing to give out installer access if they also hold
3775 // runtime permission; this is a firm CDD requirement
3776 final boolean hasInstall = mIPackageManager.checkUidPermission(INSTALL_PACKAGES,
3777 uid) == PERMISSION_GRANTED;
Sudheer Shankab1613982019-05-16 16:55:50 -07003778 boolean hasInstallOp = false;
3779 // OP_REQUEST_INSTALL_PACKAGES is granted/denied per package but vold can't
3780 // update mountpoints of a specific package. So, check the appop for all packages
3781 // sharing the uid and allow same level of storage access for all packages even if
3782 // one of the packages has the appop granted.
3783 for (String uidPackageName : packagesForUid) {
3784 if (mIAppOpsService.checkOperation(
3785 OP_REQUEST_INSTALL_PACKAGES, uid, uidPackageName) == MODE_ALLOWED) {
3786 hasInstallOp = true;
3787 break;
3788 }
3789 }
Jeff Sharkey26874a22019-04-17 21:30:47 -06003790 if ((hasInstall || hasInstallOp) && hasWrite) {
3791 return Zygote.MOUNT_EXTERNAL_WRITE;
Jeff Sharkey6fd69942019-03-26 17:53:35 -06003792 }
3793
3794 // Otherwise we're willing to give out sandboxed or non-sandboxed if
3795 // they hold the runtime permission
3796 final boolean hasLegacy = mIAppOpsService.checkOperation(OP_LEGACY_STORAGE,
3797 uid, packageName) == MODE_ALLOWED;
Jeff Sharkey26874a22019-04-17 21:30:47 -06003798 if (hasLegacy && hasWrite) {
3799 return Zygote.MOUNT_EXTERNAL_WRITE;
3800 } else if (hasLegacy && hasRead) {
3801 return Zygote.MOUNT_EXTERNAL_READ;
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -08003802 } else {
Sudheer Shanka783c90e2019-04-12 13:55:20 -07003803 return Zygote.MOUNT_EXTERNAL_DEFAULT;
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -08003804 }
3805 } catch (RemoteException e) {
3806 // Should not happen
3807 }
3808 return Zygote.MOUNT_EXTERNAL_NONE;
3809 }
3810
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003811 private static class Callbacks extends Handler {
3812 private static final int MSG_STORAGE_STATE_CHANGED = 1;
3813 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003814 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
3815 private static final int MSG_VOLUME_FORGOTTEN = 4;
3816 private static final int MSG_DISK_SCANNED = 5;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003817 private static final int MSG_DISK_DESTROYED = 6;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003818
Sudheer Shanka2250d562016-11-07 15:41:02 -08003819 private final RemoteCallbackList<IStorageEventListener>
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003820 mCallbacks = new RemoteCallbackList<>();
3821
3822 public Callbacks(Looper looper) {
3823 super(looper);
3824 }
3825
Sudheer Shanka2250d562016-11-07 15:41:02 -08003826 public void register(IStorageEventListener callback) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003827 mCallbacks.register(callback);
3828 }
3829
Sudheer Shanka2250d562016-11-07 15:41:02 -08003830 public void unregister(IStorageEventListener callback) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003831 mCallbacks.unregister(callback);
3832 }
3833
3834 @Override
3835 public void handleMessage(Message msg) {
3836 final SomeArgs args = (SomeArgs) msg.obj;
3837 final int n = mCallbacks.beginBroadcast();
3838 for (int i = 0; i < n; i++) {
Sudheer Shanka2250d562016-11-07 15:41:02 -08003839 final IStorageEventListener callback = mCallbacks.getBroadcastItem(i);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003840 try {
3841 invokeCallback(callback, msg.what, args);
3842 } catch (RemoteException ignored) {
3843 }
3844 }
3845 mCallbacks.finishBroadcast();
3846 args.recycle();
3847 }
3848
Sudheer Shanka2250d562016-11-07 15:41:02 -08003849 private void invokeCallback(IStorageEventListener callback, int what, SomeArgs args)
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003850 throws RemoteException {
3851 switch (what) {
3852 case MSG_STORAGE_STATE_CHANGED: {
3853 callback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
3854 (String) args.arg3);
3855 break;
3856 }
3857 case MSG_VOLUME_STATE_CHANGED: {
3858 callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
3859 break;
3860 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07003861 case MSG_VOLUME_RECORD_CHANGED: {
3862 callback.onVolumeRecordChanged((VolumeRecord) args.arg1);
3863 break;
3864 }
3865 case MSG_VOLUME_FORGOTTEN: {
3866 callback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003867 break;
3868 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003869 case MSG_DISK_SCANNED: {
3870 callback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003871 break;
3872 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003873 case MSG_DISK_DESTROYED: {
3874 callback.onDiskDestroyed((DiskInfo) args.arg1);
3875 break;
3876 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003877 }
3878 }
3879
3880 private void notifyStorageStateChanged(String path, String oldState, String newState) {
3881 final SomeArgs args = SomeArgs.obtain();
3882 args.arg1 = path;
3883 args.arg2 = oldState;
3884 args.arg3 = newState;
3885 obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
3886 }
3887
3888 private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
3889 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003890 args.arg1 = vol.clone();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003891 args.argi2 = oldState;
3892 args.argi3 = newState;
3893 obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
3894 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003895
Jeff Sharkey50a05452015-04-29 11:24:52 -07003896 private void notifyVolumeRecordChanged(VolumeRecord rec) {
3897 final SomeArgs args = SomeArgs.obtain();
3898 args.arg1 = rec.clone();
3899 obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
3900 }
3901
3902 private void notifyVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003903 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003904 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003905 obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003906 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003907
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003908 private void notifyDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003909 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003910 args.arg1 = disk.clone();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003911 args.argi2 = volumeCount;
3912 obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003913 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003914
3915 private void notifyDiskDestroyed(DiskInfo disk) {
3916 final SomeArgs args = SomeArgs.obtain();
3917 args.arg1 = disk.clone();
3918 obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
3919 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003920 }
3921
Kenny Root38cf8862010-09-26 14:18:51 -07003922 @Override
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003923 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003924 if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003925
3926 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003927 synchronized (mLock) {
3928 pw.println("Disks:");
3929 pw.increaseIndent();
3930 for (int i = 0; i < mDisks.size(); i++) {
3931 final DiskInfo disk = mDisks.valueAt(i);
3932 disk.dump(pw);
3933 }
3934 pw.decreaseIndent();
3935
3936 pw.println();
3937 pw.println("Volumes:");
3938 pw.increaseIndent();
3939 for (int i = 0; i < mVolumes.size(); i++) {
3940 final VolumeInfo vol = mVolumes.valueAt(i);
3941 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue;
3942 vol.dump(pw);
3943 }
3944 pw.decreaseIndent();
3945
3946 pw.println();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003947 pw.println("Records:");
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003948 pw.increaseIndent();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003949 for (int i = 0; i < mRecords.size(); i++) {
3950 final VolumeRecord note = mRecords.valueAt(i);
3951 note.dump(pw);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003952 }
3953 pw.decreaseIndent();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07003954
3955 pw.println();
3956 pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
Jeff Sharkeyb0c363b22018-12-15 11:53:03 -07003957
3958 pw.println();
Felipe Leme281389a2016-10-10 17:12:20 -07003959 final Pair<String, Long> pair = StorageManager.getPrimaryStoragePathAndSize();
3960 if (pair == null) {
3961 pw.println("Internal storage total size: N/A");
3962 } else {
3963 pw.print("Internal storage (");
3964 pw.print(pair.first);
3965 pw.print(") total size: ");
3966 pw.print(pair.second);
3967 pw.print(" (");
Jeff Sharkey9f2dc052018-01-07 16:47:31 -07003968 pw.print(DataUnit.MEBIBYTES.toBytes(pair.second));
3969 pw.println(" MiB)");
Felipe Leme281389a2016-10-10 17:12:20 -07003970 }
Jeff Sharkeyb0c363b22018-12-15 11:53:03 -07003971
3972 pw.println();
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003973 pw.println("Local unlocked users: " + Arrays.toString(mLocalUnlockedUsers));
3974 pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
Jeff Sharkeyb0c363b22018-12-15 11:53:03 -07003975
3976 final ContentResolver cr = mContext.getContentResolver();
3977 pw.println();
3978 pw.println("Isolated storage, local feature flag: "
3979 + Settings.Global.getInt(cr, Settings.Global.ISOLATED_STORAGE_LOCAL, 0));
3980 pw.println("Isolated storage, remote feature flag: "
3981 + Settings.Global.getInt(cr, Settings.Global.ISOLATED_STORAGE_REMOTE, 0));
3982 pw.println("Isolated storage, resolved: " + StorageManager.hasIsolatedStorage());
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003983 }
Kenny Root38cf8862010-09-26 14:18:51 -07003984
Kenny Root38cf8862010-09-26 14:18:51 -07003985 synchronized (mObbMounts) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003986 pw.println();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003987 pw.println("mObbMounts:");
3988 pw.increaseIndent();
3989 final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet()
3990 .iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003991 while (binders.hasNext()) {
3992 Entry<IBinder, List<ObbState>> e = binders.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003993 pw.println(e.getKey() + ":");
3994 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003995 final List<ObbState> obbStates = e.getValue();
Kenny Root38cf8862010-09-26 14:18:51 -07003996 for (final ObbState obbState : obbStates) {
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003997 pw.println(obbState);
Kenny Root38cf8862010-09-26 14:18:51 -07003998 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003999 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07004000 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004001 pw.decreaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07004002
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004003 pw.println();
4004 pw.println("mObbPathToStateMap:");
4005 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07004006 final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
4007 while (maps.hasNext()) {
4008 final Entry<String, ObbState> e = maps.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004009 pw.print(e.getKey());
4010 pw.print(" -> ");
4011 pw.println(e.getValue());
Kenny Rootaf9d6672010-10-08 09:21:39 -07004012 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004013 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07004014 }
Kenny Root4161f9b2011-07-13 09:48:33 -07004015
Robert Greenwalt470fd722012-01-18 12:51:15 -08004016 pw.println();
Christopher Tate7265abe2014-11-21 13:54:45 -08004017 pw.print("Last maintenance: ");
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07004018 pw.println(TimeUtils.formatForLogging(mLastMaintenance));
Kenny Root38cf8862010-09-26 14:18:51 -07004019 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004020
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07004021 /** {@inheritDoc} */
Jeff Sharkey48877892015-03-18 11:27:19 -07004022 @Override
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07004023 public void monitor() {
Jeff Sharkey54402792017-09-15 16:05:19 -06004024 try {
4025 mVold.monitor();
4026 } catch (Exception e) {
4027 Slog.wtf(TAG, e);
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07004028 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07004029 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07004030
Sudheer Shanka2250d562016-11-07 15:41:02 -08004031 private final class StorageManagerInternalImpl extends StorageManagerInternal {
Svet Ganov6ee871e2015-07-10 14:29:33 -07004032 // Not guarded by a lock.
4033 private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
4034 new CopyOnWriteArrayList<>();
4035
Risanaec0ee72018-10-31 10:10:12 +09004036 @GuardedBy("mResetListeners")
4037 private final List<StorageManagerInternal.ResetListener> mResetListeners =
4038 new ArrayList<>();
4039
Svet Ganov6ee871e2015-07-10 14:29:33 -07004040 @Override
4041 public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
4042 // No locking - CopyOnWriteArrayList
4043 mPolicies.add(policy);
4044 }
4045
4046 @Override
4047 public void onExternalStoragePolicyChanged(int uid, String packageName) {
4048 final int mountMode = getExternalStorageMountMode(uid, packageName);
4049 remountUidExternalStorage(uid, mountMode);
4050 }
4051
4052 @Override
4053 public int getExternalStorageMountMode(int uid, String packageName) {
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -08004054 if (ENABLE_ISOLATED_STORAGE) {
4055 return getMountMode(uid, packageName);
4056 }
Sudheer Shankab1613982019-05-16 16:55:50 -07004057 try {
4058 if (packageName == null) {
4059 final String[] packagesForUid = mIPackageManager.getPackagesForUid(uid);
4060 packageName = packagesForUid[0];
4061 }
4062 } catch (RemoteException e) {
4063 // Should not happen - same process
4064 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07004065 // No locking - CopyOnWriteArrayList
4066 int mountMode = Integer.MAX_VALUE;
4067 for (ExternalStorageMountPolicy policy : mPolicies) {
4068 final int policyMode = policy.getMountMode(uid, packageName);
4069 if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
4070 return Zygote.MOUNT_EXTERNAL_NONE;
4071 }
4072 mountMode = Math.min(mountMode, policyMode);
4073 }
4074 if (mountMode == Integer.MAX_VALUE) {
4075 return Zygote.MOUNT_EXTERNAL_NONE;
4076 }
4077 return mountMode;
4078 }
4079
Risanaec0ee72018-10-31 10:10:12 +09004080 @Override
4081 public void addResetListener(StorageManagerInternal.ResetListener listener) {
4082 synchronized (mResetListeners) {
4083 mResetListeners.add(listener);
4084 }
4085 }
4086
4087 public void onReset(IVold vold) {
4088 synchronized (mResetListeners) {
4089 for (StorageManagerInternal.ResetListener listener : mResetListeners) {
4090 listener.onReset(vold);
4091 }
4092 }
4093 }
4094
Svet Ganov6ee871e2015-07-10 14:29:33 -07004095 public boolean hasExternalStorage(int uid, String packageName) {
Amith Yamasani2bd5cff2015-07-22 14:42:31 -07004096 // No need to check for system uid. This avoids a deadlock between
4097 // PackageManagerService and AppOpsService.
4098 if (uid == Process.SYSTEM_UID) {
4099 return true;
4100 }
Sudheer Shanka3a0df3b2018-12-12 12:43:43 -08004101 if (ENABLE_ISOLATED_STORAGE) {
4102 return getMountMode(uid, packageName) != Zygote.MOUNT_EXTERNAL_NONE;
4103 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07004104 // No locking - CopyOnWriteArrayList
4105 for (ExternalStorageMountPolicy policy : mPolicies) {
4106 final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
4107 if (!policyHasStorage) {
4108 return false;
4109 }
4110 }
4111 return true;
4112 }
Sudheer Shankab1613982019-05-16 16:55:50 -07004113
4114 public void onAppOpsChanged(int code, int uid,
4115 @Nullable String packageName, int mode) {
4116 if (mode == MODE_ALLOWED && (code == OP_READ_EXTERNAL_STORAGE
4117 || code == OP_WRITE_EXTERNAL_STORAGE
4118 || code == OP_REQUEST_INSTALL_PACKAGES)) {
4119 final long token = Binder.clearCallingIdentity();
4120 try {
4121 final UserManagerInternal userManagerInternal =
4122 LocalServices.getService(UserManagerInternal.class);
4123 if (userManagerInternal.isUserInitialized(UserHandle.getUserId(uid))) {
4124 onExternalStoragePolicyChanged(uid, packageName);
4125 }
4126 } finally {
4127 Binder.restoreCallingIdentity(token);
4128 }
4129 }
4130 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07004131 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07004132}