blob: 383cc8b3170da361dc62c8f51cc065509d40b086 [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
Jeff Sharkey4c099d02015-05-15 13:45:00 -070019import static com.android.internal.util.XmlUtils.readBooleanAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070020import static com.android.internal.util.XmlUtils.readIntAttribute;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070021import static com.android.internal.util.XmlUtils.readLongAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070022import static com.android.internal.util.XmlUtils.readStringAttribute;
Jeff Sharkey4c099d02015-05-15 13:45:00 -070023import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070024import static com.android.internal.util.XmlUtils.writeIntAttribute;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070025import static com.android.internal.util.XmlUtils.writeLongAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070026import static com.android.internal.util.XmlUtils.writeStringAttribute;
Jeff Sharkey5217cac2015-12-20 15:34:01 -070027
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070028import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
29import static org.xmlpull.v1.XmlPullParser.START_TAG;
30
Jason parks8888c592011-01-20 22:46:41 -060031import android.Manifest;
Jeff Sharkeyef10ee02015-07-05 14:17:27 -070032import android.annotation.Nullable;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -070033import android.app.ActivityManager;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -070034import android.app.AppOpsManager;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070035import android.app.IActivityManager;
Jeff Sharkey9bed0702017-01-23 20:37:05 -070036import android.app.usage.StorageStatsManager;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070037import android.content.BroadcastReceiver;
Kenny Roota02b8b02010-08-05 16:14:17 -070038import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.content.Context;
40import android.content.Intent;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070041import android.content.IntentFilter;
Kenny Roota02b8b02010-08-05 16:14:17 -070042import android.content.ServiceConnection;
Jeff Sharkey275e3e42015-04-24 16:10:32 -070043import android.content.pm.IPackageMoveObserver;
44import android.content.pm.PackageManager;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070045import android.content.pm.ProviderInfo;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070046import android.content.pm.UserInfo;
Elliott Hughesf839b4f2014-09-26 12:30:47 -070047import android.content.res.Configuration;
Kenny Root02c87302010-07-01 08:10:18 -070048import android.content.res.ObbInfo;
Felipe Leme281389a2016-10-10 17:12:20 -070049import android.net.TrafficStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.net.Uri;
Kenny Root02c87302010-07-01 08:10:18 -070051import android.os.Binder;
Jeff Sharkey4c099d02015-05-15 13:45:00 -070052import android.os.DropBoxManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070053import android.os.Environment;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070054import android.os.Environment.UserEnvironment;
Jeff Sharkey48877892015-03-18 11:27:19 -070055import android.os.FileUtils;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080056import android.os.Handler;
Dianne Hackbornefa92b22013-05-03 14:11:43 -070057import android.os.HandlerThread;
Kenny Roota02b8b02010-08-05 16:14:17 -070058import android.os.IBinder;
Daniel Sandler5f27ef42010-03-16 15:42:02 -040059import android.os.Looper;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080060import android.os.Message;
Daichi Hirono9e8d9e22015-11-13 14:37:00 +090061import android.os.ParcelFileDescriptor;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -070062import android.os.ParcelableException;
Jeff Sharkeyce14cd02015-12-07 15:35:42 -070063import android.os.PowerManager;
Jeff Sharkey9527b222015-06-24 15:24:48 -070064import android.os.Process;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070065import android.os.RemoteCallbackList;
San Mehat4270e1e2010-01-29 05:32:19 -080066import android.os.RemoteException;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -080067import android.os.ServiceManager;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -070068import android.os.SystemClock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070070import android.os.UserHandle;
Emily Bernier92aa5a22014-07-07 10:11:48 -040071import android.os.UserManager;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070072import android.os.storage.DiskInfo;
Kenny Roota02b8b02010-08-05 16:14:17 -070073import android.os.storage.IObbActionListener;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070074import android.os.storage.IStorageEventListener;
Sudheer Shanka2250d562016-11-07 15:41:02 -080075import android.os.storage.IStorageManager;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070076import android.os.storage.IStorageShutdownObserver;
Kenny Rootaf9d6672010-10-08 09:21:39 -070077import android.os.storage.OnObbStateChangeListener;
Paul Lawrence46791e72014-04-03 09:10:26 -070078import android.os.storage.StorageManager;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070079import android.os.storage.StorageManagerInternal;
Kenny Roota02b8b02010-08-05 16:14:17 -070080import android.os.storage.StorageResultCode;
Mike Lockwood2f6a3882011-05-09 19:08:06 -070081import android.os.storage.StorageVolume;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070082import android.os.storage.VolumeInfo;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070083import android.os.storage.VolumeRecord;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070084import android.provider.MediaStore;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070085import android.provider.Settings;
Jason parksf7b3cd42011-01-27 09:28:25 -060086import android.text.TextUtils;
Jeff Sharkey1783f142015-04-17 10:52:51 -070087import android.text.format.DateUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -070088import android.util.ArrayMap;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070089import android.util.AtomicFile;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070090import android.util.Log;
Felipe Leme281389a2016-10-10 17:12:20 -070091import android.util.Pair;
San Mehata5078592010-03-25 09:36:54 -070092import android.util.Slog;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070093import android.util.TimeUtils;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070094import android.util.Xml;
Jeff Sharkey48877892015-03-18 11:27:19 -070095
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -080096import com.android.internal.annotations.GuardedBy;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070097import com.android.internal.app.IMediaContainerService;
Daichi Hirono9fb00182016-11-08 14:12:17 +090098import com.android.internal.os.AppFuseMount;
Daichi Hirono812c95d2017-02-08 16:20:20 +090099import com.android.internal.os.FuseUnavailableMountException;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700100import com.android.internal.os.SomeArgs;
Jeff Sharkey9527b222015-06-24 15:24:48 -0700101import com.android.internal.os.Zygote;
Jeff Sharkey48877892015-03-18 11:27:19 -0700102import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600103import com.android.internal.util.DumpUtils;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700104import com.android.internal.util.FastXmlSerializer;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800105import com.android.internal.util.HexDump;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -0700106import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700107import com.android.internal.util.Preconditions;
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700108import com.android.internal.widget.LockPatternUtils;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700109import com.android.server.NativeDaemonConnector.Command;
Jeff Sharkey56cd6462013-06-07 15:09:15 -0700110import com.android.server.NativeDaemonConnector.SensitiveArg;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700111import com.android.server.pm.PackageManagerService;
Daichi Hirono9fb00182016-11-08 14:12:17 +0900112import com.android.server.storage.AppFuseBridge;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700113
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700114import libcore.io.IoUtils;
115import libcore.util.EmptyArray;
116
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700117import org.xmlpull.v1.XmlPullParser;
118import org.xmlpull.v1.XmlPullParserException;
119import org.xmlpull.v1.XmlSerializer;
120
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700121import java.io.File;
Kenny Root38cf8862010-09-26 14:18:51 -0700122import java.io.FileDescriptor;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700123import java.io.FileInputStream;
124import java.io.FileNotFoundException;
Christopher Tate7265abe2014-11-21 13:54:45 -0800125import java.io.FileOutputStream;
Kenny Root05105f72010-09-22 17:29:43 -0700126import java.io.IOException;
Kenny Root38cf8862010-09-26 14:18:51 -0700127import java.io.PrintWriter;
Kenny Root3b1abba2010-10-13 15:00:07 -0700128import java.math.BigInteger;
Paul Lawrence8e397362014-01-27 15:22:30 -0800129import java.nio.charset.StandardCharsets;
Kenny Root735de3b2010-09-30 14:11:39 -0700130import java.security.NoSuchAlgorithmException;
Kenny Root3b1abba2010-10-13 15:00:07 -0700131import java.security.spec.InvalidKeySpecException;
132import java.security.spec.KeySpec;
San Mehat22dd86e2010-01-12 12:21:18 -0800133import java.util.ArrayList;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800134import java.util.Arrays;
Kenny Roota02b8b02010-08-05 16:14:17 -0700135import java.util.HashMap;
San Mehat6cdd9c02010-02-09 14:45:20 -0800136import java.util.HashSet;
Kenny Root38cf8862010-09-26 14:18:51 -0700137import java.util.Iterator;
Kenny Roota02b8b02010-08-05 16:14:17 -0700138import java.util.LinkedList;
139import java.util.List;
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700140import java.util.Locale;
Kenny Roota02b8b02010-08-05 16:14:17 -0700141import java.util.Map;
Kenny Root38cf8862010-09-26 14:18:51 -0700142import java.util.Map.Entry;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700143import java.util.Objects;
Svet Ganov6ee871e2015-07-10 14:29:33 -0700144import java.util.concurrent.CopyOnWriteArrayList;
Kenny Root51a573c2012-05-17 13:30:28 -0700145import java.util.concurrent.CountDownLatch;
146import java.util.concurrent.TimeUnit;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700147import java.util.concurrent.TimeoutException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148
Kenny Root3b1abba2010-10-13 15:00:07 -0700149import javax.crypto.SecretKey;
150import javax.crypto.SecretKeyFactory;
151import javax.crypto.spec.PBEKeySpec;
152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153/**
Jeff Sharkey48877892015-03-18 11:27:19 -0700154 * Service responsible for various storage media. Connects to {@code vold} to
155 * watch for and manage dynamically added storage, such as SD cards and USB mass
156 * storage. Also decides how storage should be presented to users on the device.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 */
Sudheer Shanka2250d562016-11-07 15:41:02 -0800158class StorageManagerService extends IStorageManager.Stub
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700159 implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
Jason parks5af0b912010-11-29 09:05:25 -0600160
Christopher Tated417d622013-08-19 16:14:25 -0700161 // Static direct instance pointer for the tightly-coupled idle service to use
Sudheer Shanka2250d562016-11-07 15:41:02 -0800162 static StorageManagerService sSelf = null;
Christopher Tated417d622013-08-19 16:14:25 -0700163
Jeff Sharkey56e62932015-03-21 20:41:00 -0700164 public static class Lifecycle extends SystemService {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800165 private StorageManagerService mStorageManagerService;
Jeff Sharkey56e62932015-03-21 20:41:00 -0700166
167 public Lifecycle(Context context) {
168 super(context);
169 }
170
171 @Override
172 public void onStart() {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800173 mStorageManagerService = new StorageManagerService(getContext());
174 publishBinderService("mount", mStorageManagerService);
175 mStorageManagerService.start();
Jeff Sharkey56e62932015-03-21 20:41:00 -0700176 }
177
178 @Override
179 public void onBootPhase(int phase) {
180 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800181 mStorageManagerService.systemReady();
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900182 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800183 mStorageManagerService.bootCompleted();
Jeff Sharkey56e62932015-03-21 20:41:00 -0700184 }
185 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700186
187 @Override
Jeff Sharkeyab15c392016-05-05 11:45:01 -0600188 public void onSwitchUser(int userHandle) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800189 mStorageManagerService.mCurrentUserId = userHandle;
Jeff Sharkeyab15c392016-05-05 11:45:01 -0600190 }
191
192 @Override
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700193 public void onUnlockUser(int userHandle) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800194 mStorageManagerService.onUnlockUser(userHandle);
Jeff Sharkey48877892015-03-18 11:27:19 -0700195 }
196
197 @Override
198 public void onCleanupUser(int userHandle) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800199 mStorageManagerService.onCleanupUser(userHandle);
Jeff Sharkey48877892015-03-18 11:27:19 -0700200 }
Jeff Sharkey56e62932015-03-21 20:41:00 -0700201 }
202
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800203 private static final boolean DEBUG_EVENTS = false;
Kenny Rootb7db2722011-01-25 16:39:35 -0800204 private static final boolean DEBUG_OBB = false;
Kenny Root02c87302010-07-01 08:10:18 -0700205
Kenny Root07714d42011-08-17 17:49:28 -0700206 // Disable this since it messes up long-running cryptfs operations.
207 private static final boolean WATCHDOG_ENABLE = false;
208
Jeff Sharkey00455bf2016-11-04 14:45:24 -0600209 /**
210 * Our goal is for all Android devices to be usable as development devices,
211 * which includes the new Direct Boot mode added in N. For devices that
212 * don't have native FBE support, we offer an emulation mode for developer
213 * testing purposes, but if it's prohibitively difficult to support this
214 * mode, it can be disabled for specific products using this flag.
215 */
216 private static final boolean EMULATE_FBE_SUPPORTED = true;
217
Sudheer Shanka2250d562016-11-07 15:41:02 -0800218 private static final String TAG = "StorageManagerService";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700219
Jeff Sharkey9756d752015-05-14 21:07:42 -0700220 private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700221 private static final String TAG_STORAGE_TRIM = "storage_trim";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222
Kenny Root305bcbf2010-09-03 07:56:38 -0700223 private static final String VOLD_TAG = "VoldConnector";
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700224 private static final String CRYPTD_TAG = "CryptdConnector";
Kenny Root305bcbf2010-09-03 07:56:38 -0700225
Kenny Rootcf0b38c2011-03-22 14:17:59 -0700226 /** Maximum number of ASEC containers allowed to be mounted. */
227 private static final int MAX_CONTAINERS = 250;
228
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700229 /** Magic value sent by MoveTask.cpp */
230 private static final int MOVE_STATUS_COPY_FINISHED = 82;
231
San Mehat4270e1e2010-01-29 05:32:19 -0800232 /*
233 * Internal vold response code constants
234 */
San Mehat22dd86e2010-01-12 12:21:18 -0800235 class VoldResponseCode {
San Mehat4270e1e2010-01-29 05:32:19 -0800236 /*
237 * 100 series - Requestion action was initiated; expect another reply
238 * before proceeding with a new command.
239 */
San Mehat22dd86e2010-01-12 12:21:18 -0800240 public static final int VolumeListResult = 110;
241 public static final int AsecListResult = 111;
San Mehatc1b4ce92010-02-16 17:13:03 -0800242 public static final int StorageUsersListResult = 112;
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700243 public static final int CryptfsGetfieldResult = 113;
San Mehat22dd86e2010-01-12 12:21:18 -0800244
San Mehat4270e1e2010-01-29 05:32:19 -0800245 /*
246 * 200 series - Requestion action has been successfully completed.
247 */
248 public static final int ShareStatusResult = 210;
San Mehat22dd86e2010-01-12 12:21:18 -0800249 public static final int AsecPathResult = 211;
San Mehat4270e1e2010-01-29 05:32:19 -0800250 public static final int ShareEnabledResult = 212;
San Mehat22dd86e2010-01-12 12:21:18 -0800251
San Mehat4270e1e2010-01-29 05:32:19 -0800252 /*
253 * 400 series - Command was accepted, but the requested action
254 * did not take place.
255 */
256 public static final int OpFailedNoMedia = 401;
257 public static final int OpFailedMediaBlank = 402;
258 public static final int OpFailedMediaCorrupt = 403;
259 public static final int OpFailedVolNotMounted = 404;
San Mehatd9709982010-02-18 11:43:03 -0800260 public static final int OpFailedStorageBusy = 405;
San Mehat2d66cef2010-03-23 11:12:52 -0700261 public static final int OpFailedStorageNotFound = 406;
San Mehat4270e1e2010-01-29 05:32:19 -0800262
263 /*
264 * 600 series - Unsolicited broadcasts.
265 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700266 public static final int DISK_CREATED = 640;
267 public static final int DISK_SIZE_CHANGED = 641;
268 public static final int DISK_LABEL_CHANGED = 642;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700269 public static final int DISK_SCANNED = 643;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700270 public static final int DISK_SYS_PATH_CHANGED = 644;
Jeff Sharkey48877892015-03-18 11:27:19 -0700271 public static final int DISK_DESTROYED = 649;
272
273 public static final int VOLUME_CREATED = 650;
274 public static final int VOLUME_STATE_CHANGED = 651;
275 public static final int VOLUME_FS_TYPE_CHANGED = 652;
276 public static final int VOLUME_FS_UUID_CHANGED = 653;
277 public static final int VOLUME_FS_LABEL_CHANGED = 654;
278 public static final int VOLUME_PATH_CHANGED = 655;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700279 public static final int VOLUME_INTERNAL_PATH_CHANGED = 656;
Jeff Sharkey48877892015-03-18 11:27:19 -0700280 public static final int VOLUME_DESTROYED = 659;
Svetoslavf23b64d2013-04-25 14:45:54 -0700281
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700282 public static final int MOVE_STATUS = 660;
Jeff Sharkey9756d752015-05-14 21:07:42 -0700283 public static final int BENCHMARK_RESULT = 661;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700284 public static final int TRIM_RESULT = 662;
San Mehat22dd86e2010-01-12 12:21:18 -0800285 }
286
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700287 private static final int VERSION_INIT = 1;
288 private static final int VERSION_ADD_PRIMARY = 2;
Jeff Sharkeyfced5342015-05-10 14:53:34 -0700289 private static final int VERSION_FIX_PRIMARY = 3;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700290
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700291 private static final String TAG_VOLUMES = "volumes";
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700292 private static final String ATTR_VERSION = "version";
293 private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid";
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700294 private static final String ATTR_FORCE_ADOPTABLE = "forceAdoptable";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700295 private static final String TAG_VOLUME = "volume";
296 private static final String ATTR_TYPE = "type";
297 private static final String ATTR_FS_UUID = "fsUuid";
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700298 private static final String ATTR_PART_GUID = "partGuid";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700299 private static final String ATTR_NICKNAME = "nickname";
300 private static final String ATTR_USER_FLAGS = "userFlags";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700301 private static final String ATTR_CREATED_MILLIS = "createdMillis";
302 private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis";
303 private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700304
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700305 private final AtomicFile mSettingsFile;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700306
Jeff Sharkey48877892015-03-18 11:27:19 -0700307 /**
308 * <em>Never</em> hold the lock while performing downcalls into vold, since
309 * unsolicited events can suddenly appear to update data structures.
310 */
Jeff Sharkey5f3e9342017-03-13 14:53:11 -0600311 private final Object mLock = LockGuard.installNewLock(LockGuard.INDEX_STORAGE);
Jeff Sharkey48877892015-03-18 11:27:19 -0700312
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700313 /** Set of users that we know are unlocked. */
Jeff Sharkey48877892015-03-18 11:27:19 -0700314 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700315 private int[] mLocalUnlockedUsers = EmptyArray.INT;
316 /** Set of users that system knows are unlocked. */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800317 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700318 private int[] mSystemUnlockedUsers = EmptyArray.INT;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700319
320 /** Map from disk ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700321 @GuardedBy("mLock")
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700322 private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700323 /** Map from volume ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700324 @GuardedBy("mLock")
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700325 private final ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
Jeff Sharkey48877892015-03-18 11:27:19 -0700326
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700327 /** Map from UUID to record */
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700328 @GuardedBy("mLock")
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700329 private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>();
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700330 @GuardedBy("mLock")
331 private String mPrimaryStorageUuid;
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700332 @GuardedBy("mLock")
333 private boolean mForceAdoptable;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700334
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700335 /** Map from disk ID to latches */
336 @GuardedBy("mLock")
337 private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
338
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700339 @GuardedBy("mLock")
340 private IPackageMoveObserver mMoveCallback;
341 @GuardedBy("mLock")
342 private String mMoveTargetUuid;
343
Jeff Sharkeyab15c392016-05-05 11:45:01 -0600344 private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
345
Daichi Hirono9fb00182016-11-08 14:12:17 +0900346 /** Holding lock for AppFuse business */
347 private final Object mAppFuseLock = new Object();
348
349 @GuardedBy("mAppFuseLock")
350 private int mNextAppFuseName = 0;
351
352 @GuardedBy("mAppFuseLock")
Daichi Hironoe56740d2017-02-02 13:56:45 +0900353 private AppFuseBridge mAppFuseBridge = null;
Daichi Hirono9fb00182016-11-08 14:12:17 +0900354
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700355 private VolumeInfo findVolumeByIdOrThrow(String id) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700356 synchronized (mLock) {
357 final VolumeInfo vol = mVolumes.get(id);
358 if (vol != null) {
359 return vol;
360 }
361 }
362 throw new IllegalArgumentException("No volume found for ID " + id);
363 }
364
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700365 private String findVolumeIdForPathOrThrow(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700366 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700367 for (int i = 0; i < mVolumes.size(); i++) {
368 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700369 if (vol.path != null && path.startsWith(vol.path)) {
370 return vol.id;
Jeff Sharkey48877892015-03-18 11:27:19 -0700371 }
372 }
373 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700374 throw new IllegalArgumentException("No volume found for path " + path);
Jeff Sharkey48877892015-03-18 11:27:19 -0700375 }
376
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700377 private VolumeRecord findRecordForPath(String path) {
378 synchronized (mLock) {
379 for (int i = 0; i < mVolumes.size(); i++) {
380 final VolumeInfo vol = mVolumes.valueAt(i);
381 if (vol.path != null && path.startsWith(vol.path)) {
382 return mRecords.get(vol.fsUuid);
383 }
384 }
385 }
386 return null;
387 }
388
389 private String scrubPath(String path) {
390 if (path.startsWith(Environment.getDataDirectory().getAbsolutePath())) {
391 return "internal";
392 }
393 final VolumeRecord rec = findRecordForPath(path);
394 if (rec == null || rec.createdMillis == 0) {
395 return "unknown";
396 } else {
397 return "ext:" + (int) ((System.currentTimeMillis() - rec.createdMillis)
398 / DateUtils.WEEK_IN_MILLIS) + "w";
399 }
400 }
401
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700402 private @Nullable VolumeInfo findStorageForUuid(String volumeUuid) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700403 final StorageManager storage = mContext.getSystemService(StorageManager.class);
404 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700405 return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL);
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700406 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
407 return storage.getPrimaryPhysicalVolume();
408 } else {
409 return storage.findEmulatedForPrivate(storage.findVolumeByUuid(volumeUuid));
410 }
411 }
412
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700413 private boolean shouldBenchmark() {
414 final long benchInterval = Settings.Global.getLong(mContext.getContentResolver(),
415 Settings.Global.STORAGE_BENCHMARK_INTERVAL, DateUtils.WEEK_IN_MILLIS);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700416 if (benchInterval == -1) {
417 return false;
418 } else if (benchInterval == 0) {
419 return true;
420 }
421
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700422 synchronized (mLock) {
423 for (int i = 0; i < mVolumes.size(); i++) {
424 final VolumeInfo vol = mVolumes.valueAt(i);
425 final VolumeRecord rec = mRecords.get(vol.fsUuid);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700426 if (vol.isMountedWritable() && rec != null) {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700427 final long benchAge = System.currentTimeMillis() - rec.lastBenchMillis;
428 if (benchAge >= benchInterval) {
429 return true;
430 }
431 }
432 }
433 return false;
434 }
435 }
436
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700437 private CountDownLatch findOrCreateDiskScanLatch(String diskId) {
438 synchronized (mLock) {
439 CountDownLatch latch = mDiskScanLatches.get(diskId);
440 if (latch == null) {
441 latch = new CountDownLatch(1);
442 mDiskScanLatches.put(diskId, latch);
443 }
444 return latch;
445 }
446 }
447
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800448 private static String escapeNull(String arg) {
449 if (TextUtils.isEmpty(arg)) {
450 return "!";
451 } else {
452 if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
453 throw new IllegalArgumentException(arg);
454 }
455 return arg;
456 }
457 }
458
Paul Lawrence8e397362014-01-27 15:22:30 -0800459 /** List of crypto types.
460 * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
461 * corresponding commands in CommandListener.cpp */
462 public static final String[] CRYPTO_TYPES
463 = { "password", "default", "pattern", "pin" };
464
Brian Carlstrom7395a8a2014-04-28 22:11:01 -0700465 private final Context mContext;
Jeff Sharkeycd575992016-03-29 14:12:49 -0600466
Brian Carlstromdfad99a2014-05-07 15:21:14 -0700467 private final NativeDaemonConnector mConnector;
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700468 private final NativeDaemonConnector mCryptConnector;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700469
Jeff Sharkeycd575992016-03-29 14:12:49 -0600470 private final Thread mConnectorThread;
471 private final Thread mCryptConnectorThread;
472
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700473 private volatile boolean mSystemReady = false;
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900474 private volatile boolean mBootCompleted = false;
Jeff Sharkey48877892015-03-18 11:27:19 -0700475 private volatile boolean mDaemonConnected = false;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700476
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700477 private PackageManagerService mPms;
478
479 private final Callbacks mCallbacks;
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700480 private final LockPatternUtils mLockPatternUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -0700481
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700482 // Two connectors - mConnector & mCryptConnector
483 private final CountDownLatch mConnectedSignal = new CountDownLatch(2);
Jeff Sharkey0be607c2012-11-14 14:39:19 -0800484 private final CountDownLatch mAsecsScanned = new CountDownLatch(1);
Jeff Sharkey48877892015-03-18 11:27:19 -0700485
486 private final Object mUnmountLock = new Object();
487 @GuardedBy("mUnmountLock")
488 private CountDownLatch mUnmountSignal;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800489
San Mehat6cdd9c02010-02-09 14:45:20 -0800490 /**
491 * Private hash of currently mounted secure containers.
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800492 * Used as a lock in methods to manipulate secure containers.
San Mehat6cdd9c02010-02-09 14:45:20 -0800493 */
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800494 final private HashSet<String> mAsecMountSet = new HashSet<String>();
San Mehat6cdd9c02010-02-09 14:45:20 -0800495
Kenny Root02c87302010-07-01 08:10:18 -0700496 /**
Kenny Root3b1abba2010-10-13 15:00:07 -0700497 * The size of the crypto algorithm key in bits for OBB files. Currently
498 * Twofish is used which takes 128-bit keys.
499 */
500 private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
501
502 /**
503 * The number of times to run SHA1 in the PBKDF2 function for OBB files.
504 * 1024 is reasonably secure and not too slow.
505 */
506 private static final int PBKDF2_HASH_ROUNDS = 1024;
507
508 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700509 * Mounted OBB tracking information. Used to track the current state of all
510 * OBBs.
Kenny Root02c87302010-07-01 08:10:18 -0700511 */
Kenny Root735de3b2010-09-30 14:11:39 -0700512 final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700513
514 /** Map from raw paths to {@link ObbState}. */
Kenny Roota02b8b02010-08-05 16:14:17 -0700515 final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
516
Svet Ganov6ee871e2015-07-10 14:29:33 -0700517 // Not guarded by a lock.
Sudheer Shanka2250d562016-11-07 15:41:02 -0800518 private final StorageManagerInternalImpl mStorageManagerInternal
519 = new StorageManagerInternalImpl();
Svet Ganov6ee871e2015-07-10 14:29:33 -0700520
Kenny Roota02b8b02010-08-05 16:14:17 -0700521 class ObbState implements IBinder.DeathRecipient {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700522 public ObbState(String rawPath, String canonicalPath, int callingUid,
523 IObbActionListener token, int nonce) {
524 this.rawPath = rawPath;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700525 this.canonicalPath = canonicalPath;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700526
527 this.ownerGid = UserHandle.getSharedAppGid(callingUid);
Kenny Rootaf9d6672010-10-08 09:21:39 -0700528 this.token = token;
529 this.nonce = nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700530 }
531
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700532 final String rawPath;
533 final String canonicalPath;
Kenny Roota02b8b02010-08-05 16:14:17 -0700534
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700535 final int ownerGid;
Kenny Roota02b8b02010-08-05 16:14:17 -0700536
Kenny Rootaf9d6672010-10-08 09:21:39 -0700537 // Token of remote Binder caller
538 final IObbActionListener token;
539
540 // Identifier to pass back to the token
541 final int nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700542
Kenny Root735de3b2010-09-30 14:11:39 -0700543 public IBinder getBinder() {
544 return token.asBinder();
545 }
546
Kenny Roota02b8b02010-08-05 16:14:17 -0700547 @Override
548 public void binderDied() {
549 ObbAction action = new UnmountObbAction(this, true);
550 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root735de3b2010-09-30 14:11:39 -0700551 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700552
Kenny Root5919ac62010-10-05 09:49:40 -0700553 public void link() throws RemoteException {
554 getBinder().linkToDeath(this, 0);
555 }
556
557 public void unlink() {
Kenny Root735de3b2010-09-30 14:11:39 -0700558 getBinder().unlinkToDeath(this, 0);
Kenny Roota02b8b02010-08-05 16:14:17 -0700559 }
Kenny Root38cf8862010-09-26 14:18:51 -0700560
561 @Override
562 public String toString() {
563 StringBuilder sb = new StringBuilder("ObbState{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700564 sb.append("rawPath=").append(rawPath);
565 sb.append(",canonicalPath=").append(canonicalPath);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700566 sb.append(",ownerGid=").append(ownerGid);
567 sb.append(",token=").append(token);
568 sb.append(",binder=").append(getBinder());
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;
579 private static final int OBB_MCS_BOUND = 2;
580 private static final int OBB_MCS_UNBIND = 3;
581 private static final int OBB_MCS_RECONNECT = 4;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700582 private static final int OBB_FLUSH_MOUNT_STATE = 5;
Kenny Roota02b8b02010-08-05 16:14:17 -0700583
584 /*
585 * Default Container Service information
586 */
587 static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
588 "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
589
590 final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
591
592 class DefaultContainerConnection implements ServiceConnection {
Jeff Sharkey48877892015-03-18 11:27:19 -0700593 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700594 public void onServiceConnected(ComponentName name, IBinder service) {
595 if (DEBUG_OBB)
596 Slog.i(TAG, "onServiceConnected");
597 IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
598 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
599 }
600
Jeff Sharkey48877892015-03-18 11:27:19 -0700601 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700602 public void onServiceDisconnected(ComponentName name) {
603 if (DEBUG_OBB)
604 Slog.i(TAG, "onServiceDisconnected");
605 }
606 };
607
608 // Used in the ObbActionHandler
609 private IMediaContainerService mContainerService = null;
Kenny Root02c87302010-07-01 08:10:18 -0700610
Christopher Tate7265abe2014-11-21 13:54:45 -0800611 // Last fstrim operation tracking
612 private static final String LAST_FSTRIM_FILE = "last-fstrim";
613 private final File mLastMaintenanceFile;
614 private long mLastMaintenance;
615
Kenny Root02c87302010-07-01 08:10:18 -0700616 // Handler messages
Jeff Sharkey48877892015-03-18 11:27:19 -0700617 private static final int H_SYSTEM_READY = 1;
618 private static final int H_DAEMON_CONNECTED = 2;
619 private static final int H_SHUTDOWN = 3;
620 private static final int H_FSTRIM = 4;
621 private static final int H_VOLUME_MOUNT = 5;
622 private static final int H_VOLUME_BROADCAST = 6;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700623 private static final int H_INTERNAL_BROADCAST = 7;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700624 private static final int H_VOLUME_UNMOUNT = 8;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800625 private static final int H_PARTITION_FORGET = 9;
626 private static final int H_RESET = 10;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800627
Sudheer Shanka2250d562016-11-07 15:41:02 -0800628 class StorageManagerServiceHandler extends Handler {
629 public StorageManagerServiceHandler(Looper looper) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700630 super(looper);
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400631 }
632
Jason parks5af0b912010-11-29 09:05:25 -0600633 @Override
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800634 public void handleMessage(Message msg) {
635 switch (msg.what) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700636 case H_SYSTEM_READY: {
Jeff Sharkey48877892015-03-18 11:27:19 -0700637 handleSystemReady();
638 break;
639 }
640 case H_DAEMON_CONNECTED: {
641 handleDaemonConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700642 break;
643 }
Christopher Tated417d622013-08-19 16:14:25 -0700644 case H_FSTRIM: {
Jeff Sharkey1783f142015-04-17 10:52:51 -0700645 if (!isReady()) {
646 Slog.i(TAG, "fstrim requested, but no daemon connection yet; trying again");
Christopher Tate7618db12015-04-28 16:32:55 -0700647 sendMessageDelayed(obtainMessage(H_FSTRIM, msg.obj),
648 DateUtils.SECOND_IN_MILLIS);
649 break;
Jeff Sharkey1783f142015-04-17 10:52:51 -0700650 }
651
Christopher Tated417d622013-08-19 16:14:25 -0700652 Slog.i(TAG, "Running fstrim idle maintenance");
Christopher Tate7265abe2014-11-21 13:54:45 -0800653
654 // Remember when we kicked it off
655 try {
656 mLastMaintenance = System.currentTimeMillis();
657 mLastMaintenanceFile.setLastModified(mLastMaintenance);
658 } catch (Exception e) {
659 Slog.e(TAG, "Unable to record last fstrim!");
660 }
661
Jeff Sharkey31d0b702016-11-21 14:16:53 -0700662 final int flags = shouldBenchmark() ? StorageManager.FSTRIM_FLAG_BENCHMARK : 0;
663 fstrim(flags);
Christopher Tate7265abe2014-11-21 13:54:45 -0800664
Christopher Tated417d622013-08-19 16:14:25 -0700665 // invoke the completion callback, if any
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700666 // TODO: fstrim is non-blocking, so remove this useless callback
Christopher Tated417d622013-08-19 16:14:25 -0700667 Runnable callback = (Runnable) msg.obj;
668 if (callback != null) {
669 callback.run();
670 }
671 break;
672 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700673 case H_SHUTDOWN: {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800674 final IStorageShutdownObserver obs = (IStorageShutdownObserver) msg.obj;
Jeff Sharkey48877892015-03-18 11:27:19 -0700675 boolean success = false;
676 try {
677 success = mConnector.execute("volume", "shutdown").isClassOk();
678 } catch (NativeDaemonConnectorException ignored) {
679 }
680 if (obs != null) {
681 try {
682 obs.onShutDownComplete(success ? 0 : -1);
683 } catch (RemoteException ignored) {
684 }
685 }
686 break;
687 }
688 case H_VOLUME_MOUNT: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700689 final VolumeInfo vol = (VolumeInfo) msg.obj;
Jeff Sharkey2e606d72015-07-27 14:19:54 -0700690 if (isMountDisallowed(vol)) {
691 Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");
692 break;
693 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700694 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700695 mConnector.execute("volume", "mount", vol.id, vol.mountFlags,
696 vol.mountUserId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700697 } catch (NativeDaemonConnectorException ignored) {
698 }
699 break;
700 }
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700701 case H_VOLUME_UNMOUNT: {
702 final VolumeInfo vol = (VolumeInfo) msg.obj;
703 unmount(vol.getId());
704 break;
705 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700706 case H_VOLUME_BROADCAST: {
707 final StorageVolume userVol = (StorageVolume) msg.obj;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700708 final String envState = userVol.getState();
709 Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + envState + " to "
Jeff Sharkey48877892015-03-18 11:27:19 -0700710 + userVol.getOwner());
711
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700712 final String action = VolumeInfo.getBroadcastForEnvironment(envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700713 if (action != null) {
714 final Intent intent = new Intent(action,
715 Uri.fromFile(userVol.getPathFile()));
716 intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, userVol);
Jeff Sharkey082f83b2017-03-26 14:34:47 -0600717 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
718 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Jeff Sharkey48877892015-03-18 11:27:19 -0700719 mContext.sendBroadcastAsUser(intent, userVol.getOwner());
720 }
721 break;
722 }
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700723 case H_INTERNAL_BROADCAST: {
724 // Internal broadcasts aimed at system components, not for
725 // third-party apps.
726 final Intent intent = (Intent) msg.obj;
727 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
728 android.Manifest.permission.WRITE_MEDIA_STORAGE);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800729 break;
730 }
731 case H_PARTITION_FORGET: {
732 final String partGuid = (String) msg.obj;
733 forgetPartition(partGuid);
734 break;
735 }
736 case H_RESET: {
737 resetIfReadyAndConnected();
738 break;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700739 }
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800740 }
741 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700742 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700743
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700744 private final Handler mHandler;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800745
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700746 private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
747 @Override
748 public void onReceive(Context context, Intent intent) {
749 final String action = intent.getAction();
750 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700751 Preconditions.checkArgument(userId >= 0);
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700752
753 try {
754 if (Intent.ACTION_USER_ADDED.equals(action)) {
755 final UserManager um = mContext.getSystemService(UserManager.class);
756 final int userSerialNumber = um.getUserSerialNumber(userId);
757 mConnector.execute("volume", "user_added", userId, userSerialNumber);
758 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700759 synchronized (mVolumes) {
760 final int size = mVolumes.size();
761 for (int i = 0; i < size; i++) {
762 final VolumeInfo vol = mVolumes.valueAt(i);
763 if (vol.mountUserId == userId) {
764 vol.mountUserId = UserHandle.USER_NULL;
765 mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
766 }
767 }
768 }
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700769 mConnector.execute("volume", "user_removed", userId);
770 }
771 } catch (NativeDaemonConnectorException e) {
772 Slog.w(TAG, "Failed to send user details to vold", e);
773 }
774 }
775 };
776
Jeff Sharkey56e62932015-03-21 20:41:00 -0700777 @Override
778 public void waitForAsecScan() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700779 waitForLatch(mAsecsScanned, "mAsecsScanned");
Kenny Root51a573c2012-05-17 13:30:28 -0700780 }
781
San Mehat207e5382010-02-04 20:46:54 -0800782 private void waitForReady() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700783 waitForLatch(mConnectedSignal, "mConnectedSignal");
Kenny Root51a573c2012-05-17 13:30:28 -0700784 }
785
Jeff Sharkey48877892015-03-18 11:27:19 -0700786 private void waitForLatch(CountDownLatch latch, String condition) {
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700787 try {
788 waitForLatch(latch, condition, -1);
789 } catch (TimeoutException ignored) {
790 }
791 }
792
793 private void waitForLatch(CountDownLatch latch, String condition, long timeoutMillis)
794 throws TimeoutException {
795 final long startMillis = SystemClock.elapsedRealtime();
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700796 while (true) {
Kenny Root51a573c2012-05-17 13:30:28 -0700797 try {
798 if (latch.await(5000, TimeUnit.MILLISECONDS)) {
San Mehat207e5382010-02-04 20:46:54 -0800799 return;
Kenny Root51a573c2012-05-17 13:30:28 -0700800 } else {
801 Slog.w(TAG, "Thread " + Thread.currentThread().getName()
Jeff Sharkey48877892015-03-18 11:27:19 -0700802 + " still waiting for " + condition + "...");
San Mehat207e5382010-02-04 20:46:54 -0800803 }
Kenny Root51a573c2012-05-17 13:30:28 -0700804 } catch (InterruptedException e) {
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700805 Slog.w(TAG, "Interrupt while waiting for " + condition);
San Mehat207e5382010-02-04 20:46:54 -0800806 }
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700807 if (timeoutMillis > 0 && SystemClock.elapsedRealtime() > startMillis + timeoutMillis) {
808 throw new TimeoutException("Thread " + Thread.currentThread().getName()
809 + " gave up waiting for " + condition + " after " + timeoutMillis + "ms");
810 }
San Mehat207e5382010-02-04 20:46:54 -0800811 }
San Mehat1f6301e2010-01-07 22:40:27 -0800812 }
Kenny Root02c87302010-07-01 08:10:18 -0700813
Paul Lawrence945490c2014-03-27 16:37:28 +0000814 private boolean isReady() {
815 try {
816 return mConnectedSignal.await(0, TimeUnit.MILLISECONDS);
817 } catch (InterruptedException e) {
818 return false;
819 }
820 }
821
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700822 private void handleSystemReady() {
Jeff Sharkey8924e872015-11-30 12:52:10 -0700823 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800824 resetIfReadyAndConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700825
Jeff Sharkey48877892015-03-18 11:27:19 -0700826 // Start scheduling nominally-daily fstrim operations
Christopher Tate115afda2014-06-06 19:06:26 -0700827 MountServiceIdler.scheduleIdlePass(mContext);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700828 }
829
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700830 /**
831 * MediaProvider has a ton of code that makes assumptions about storage
832 * paths never changing, so we outright kill them to pick up new state.
833 */
834 @Deprecated
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700835 private void killMediaProvider(List<UserInfo> users) {
836 if (users == null) return;
837
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700838 final long token = Binder.clearCallingIdentity();
839 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700840 for (UserInfo user : users) {
841 // System user does not have media provider, so skip.
842 if (user.isSystemOnly()) continue;
843
Jeff Sharkey2a9e3f82015-12-18 10:57:58 -0700844 final ProviderInfo provider = mPms.resolveContentProvider(MediaStore.AUTHORITY,
Jeff Sharkey8a372a02016-03-16 16:25:45 -0600845 PackageManager.MATCH_DIRECT_BOOT_AWARE
846 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
847 user.id);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700848 if (provider != null) {
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800849 final IActivityManager am = ActivityManager.getService();
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700850 try {
Jeff Sharkey85f449e2016-06-23 09:26:00 -0600851 am.killApplication(provider.applicationInfo.packageName,
852 UserHandle.getAppId(provider.applicationInfo.uid),
853 UserHandle.USER_ALL, "vold reset");
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700854 // We only need to run this once. It will kill all users' media processes.
855 break;
856 } catch (RemoteException e) {
857 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700858 }
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700859 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700860 } finally {
861 Binder.restoreCallingIdentity(token);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700862 }
863 }
864
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800865 private void addInternalVolumeLocked() {
Amith Yamasania7892482015-08-07 11:09:05 -0700866 // Create a stub volume that represents internal storage
867 final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
868 VolumeInfo.TYPE_PRIVATE, null, null);
869 internal.state = VolumeInfo.STATE_MOUNTED;
870 internal.path = Environment.getDataDirectory().getAbsolutePath();
871 mVolumes.put(internal.id, internal);
872 }
873
Jeff Sharkey8924e872015-11-30 12:52:10 -0700874 private void initIfReadyAndConnected() {
875 Slog.d(TAG, "Thinking about init, mSystemReady=" + mSystemReady
876 + ", mDaemonConnected=" + mDaemonConnected);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700877 if (mSystemReady && mDaemonConnected
Paul Lawrence20be5d62016-02-26 13:51:17 -0800878 && !StorageManager.isFileEncryptedNativeOnly()) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700879 // When booting a device without native support, make sure that our
880 // user directories are locked or unlocked based on the current
881 // emulation status.
Paul Lawrence20be5d62016-02-26 13:51:17 -0800882 final boolean initLocked = StorageManager.isFileEncryptedEmulatedOnly();
Paul Crowleyd94ab732016-02-15 06:44:51 +0000883 Slog.d(TAG, "Setting up emulation state, initlocked=" + initLocked);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700884 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Jeff Sharkey8924e872015-11-30 12:52:10 -0700885 for (UserInfo user : users) {
886 try {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700887 if (initLocked) {
888 mCryptConnector.execute("cryptfs", "lock_user_key", user.id);
889 } else {
890 mCryptConnector.execute("cryptfs", "unlock_user_key", user.id,
Paul Crowleyd94ab732016-02-15 06:44:51 +0000891 user.serialNumber, "!", "!");
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700892 }
Jeff Sharkey8924e872015-11-30 12:52:10 -0700893 } catch (NativeDaemonConnectorException e) {
894 Slog.w(TAG, "Failed to init vold", e);
895 }
896 }
897 }
898 }
899
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800900 private void resetIfReadyAndConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700901 Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
902 + ", mDaemonConnected=" + mDaemonConnected);
903 if (mSystemReady && mDaemonConnected) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800904 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700905 killMediaProvider(users);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700906
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700907 final int[] systemUnlockedUsers;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800908 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700909 systemUnlockedUsers = mSystemUnlockedUsers;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700910
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800911 mDisks.clear();
912 mVolumes.clear();
913
914 addInternalVolumeLocked();
915 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700916
Jeff Sharkey48877892015-03-18 11:27:19 -0700917 try {
918 mConnector.execute("volume", "reset");
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700919
920 // Tell vold about all existing and started users
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700921 for (UserInfo user : users) {
922 mConnector.execute("volume", "user_added", user.id, user.serialNumber);
923 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700924 for (int userId : systemUnlockedUsers) {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700925 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey50a05452015-04-29 11:24:52 -0700926 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700927 } catch (NativeDaemonConnectorException e) {
928 Slog.w(TAG, "Failed to reset vold", e);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700929 }
930 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700931 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700932
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700933 private void onUnlockUser(int userId) {
934 Slog.d(TAG, "onUnlockUser " + userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700935
936 // We purposefully block here to make sure that user-specific
937 // staging area is ready so it's ready for zygote-forked apps to
938 // bind mount against.
939 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700940 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700941 } catch (NativeDaemonConnectorException ignored) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700942 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700943
944 // Record user as started so newly mounted volumes kick off events
945 // correctly, then synthesize events for any already-mounted volumes.
yuanhuihuiefd1f122016-07-13 21:21:03 +0800946 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700947 for (int i = 0; i < mVolumes.size(); i++) {
948 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey46349872015-07-28 10:49:47 -0700949 if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700950 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey48877892015-03-18 11:27:19 -0700951 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700952
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700953 final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
954 mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700955 }
956 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700957 mSystemUnlockedUsers = ArrayUtils.appendInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700958 }
959 }
960
961 private void onCleanupUser(int userId) {
962 Slog.d(TAG, "onCleanupUser " + userId);
963
964 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700965 mConnector.execute("volume", "user_stopped", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700966 } catch (NativeDaemonConnectorException ignored) {
967 }
968
yuanhuihuiefd1f122016-07-13 21:21:03 +0800969 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700970 mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700971 }
972 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700973
Christopher Tated417d622013-08-19 16:14:25 -0700974 void runIdleMaintenance(Runnable callback) {
975 mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
976 }
977
Christopher Tate7265abe2014-11-21 13:54:45 -0800978 // Binder entry point for kicking off an immediate fstrim
979 @Override
980 public void runMaintenance() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700981 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Christopher Tate7265abe2014-11-21 13:54:45 -0800982 runIdleMaintenance(null);
983 }
984
985 @Override
986 public long lastMaintenance() {
987 return mLastMaintenance;
988 }
989
San Mehat4270e1e2010-01-29 05:32:19 -0800990 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800991 * Callback from NativeDaemonConnector
992 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700993 @Override
San Mehat4270e1e2010-01-29 05:32:19 -0800994 public void onDaemonConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700995 mDaemonConnected = true;
996 mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();
997 }
998
999 private void handleDaemonConnected() {
Jeff Sharkey8924e872015-11-30 12:52:10 -07001000 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001001 resetIfReadyAndConnected();
Jeff Sharkey48877892015-03-18 11:27:19 -07001002
San Mehat4270e1e2010-01-29 05:32:19 -08001003 /*
Jeff Sharkey48877892015-03-18 11:27:19 -07001004 * Now that we've done our initialization, release
1005 * the hounds!
San Mehat4270e1e2010-01-29 05:32:19 -08001006 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001007 mConnectedSignal.countDown();
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001008 if (mConnectedSignal.getCount() != 0) {
1009 // More daemons need to connect
1010 return;
1011 }
Mike Lockwood7fa24aa2011-03-23 14:52:34 -04001012
Jeff Sharkey48877892015-03-18 11:27:19 -07001013 // On an encrypted device we can't see system properties yet, so pull
1014 // the system locale out of the mount service.
1015 if ("".equals(SystemProperties.get("vold.encrypt_progress"))) {
1016 copyLocaleFromMountService();
1017 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001018
Jeff Sharkey48877892015-03-18 11:27:19 -07001019 // Let package manager load internal ASECs.
1020 mPms.scanAvailableAsecs();
Mike Lockwood7fa24aa2011-03-23 14:52:34 -04001021
Jeff Sharkey48877892015-03-18 11:27:19 -07001022 // Notify people waiting for ASECs to be scanned that it's done.
1023 mAsecsScanned.countDown();
San Mehat4270e1e2010-01-29 05:32:19 -08001024 }
1025
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001026 private void copyLocaleFromMountService() {
1027 String systemLocale;
1028 try {
1029 systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
1030 } catch (RemoteException e) {
1031 return;
1032 }
1033 if (TextUtils.isEmpty(systemLocale)) {
1034 return;
1035 }
1036
1037 Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
1038 Locale locale = Locale.forLanguageTag(systemLocale);
1039 Configuration config = new Configuration();
1040 config.setLocale(locale);
1041 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001042 ActivityManager.getService().updatePersistentConfiguration(config);
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001043 } catch (RemoteException e) {
1044 Slog.e(TAG, "Error setting system locale from mount service", e);
1045 }
Elliott Hughes9c33f282014-10-13 12:39:56 -07001046
1047 // Temporary workaround for http://b/17945169.
1048 Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
Narayan Kamathd30dbb82015-01-15 14:48:15 +00001049 SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001050 }
1051
San Mehat4270e1e2010-01-29 05:32:19 -08001052 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001053 * Callback from NativeDaemonConnector
1054 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001055 @Override
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001056 public boolean onCheckHoldWakeLock(int code) {
1057 return false;
1058 }
1059
1060 /**
1061 * Callback from NativeDaemonConnector
1062 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001063 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001064 public boolean onEvent(int code, String raw, String[] cooked) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001065 synchronized (mLock) {
1066 return onEventLocked(code, raw, cooked);
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -08001067 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001068 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001069
Jeff Sharkey48877892015-03-18 11:27:19 -07001070 private boolean onEventLocked(int code, String raw, String[] cooked) {
1071 switch (code) {
1072 case VoldResponseCode.DISK_CREATED: {
1073 if (cooked.length != 3) break;
1074 final String id = cooked[1];
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001075 int flags = Integer.parseInt(cooked[2]);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001076 if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false)
1077 || mForceAdoptable) {
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001078 flags |= DiskInfo.FLAG_ADOPTABLE;
1079 }
Jeff Sharkey6ed74182016-08-23 13:53:53 -06001080 // Adoptable storage isn't currently supported on FBE devices
1081 if (StorageManager.isFileEncryptedNativeOnly()) {
1082 flags &= ~DiskInfo.FLAG_ADOPTABLE;
1083 }
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001084 mDisks.put(id, new DiskInfo(id, flags));
Jeff Sharkey48877892015-03-18 11:27:19 -07001085 break;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001086 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001087 case VoldResponseCode.DISK_SIZE_CHANGED: {
1088 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001089 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001090 if (disk != null) {
1091 disk.size = Long.parseLong(cooked[2]);
San Mehat4270e1e2010-01-29 05:32:19 -08001092 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001093 break;
1094 }
1095 case VoldResponseCode.DISK_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001096 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001097 if (disk != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001098 final StringBuilder builder = new StringBuilder();
1099 for (int i = 2; i < cooked.length; i++) {
1100 builder.append(cooked[i]).append(' ');
1101 }
1102 disk.label = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001103 }
1104 break;
1105 }
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001106 case VoldResponseCode.DISK_SCANNED: {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001107 if (cooked.length != 2) break;
1108 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001109 if (disk != null) {
1110 onDiskScannedLocked(disk);
1111 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -07001112 break;
1113 }
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001114 case VoldResponseCode.DISK_SYS_PATH_CHANGED: {
1115 if (cooked.length != 3) break;
1116 final DiskInfo disk = mDisks.get(cooked[1]);
1117 if (disk != null) {
1118 disk.sysPath = cooked[2];
1119 }
1120 break;
1121 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001122 case VoldResponseCode.DISK_DESTROYED: {
1123 if (cooked.length != 2) break;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07001124 final DiskInfo disk = mDisks.remove(cooked[1]);
1125 if (disk != null) {
1126 mCallbacks.notifyDiskDestroyed(disk);
1127 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001128 break;
1129 }
San Mehat4270e1e2010-01-29 05:32:19 -08001130
Jeff Sharkey48877892015-03-18 11:27:19 -07001131 case VoldResponseCode.VOLUME_CREATED: {
Jeff Sharkey48877892015-03-18 11:27:19 -07001132 final String id = cooked[1];
1133 final int type = Integer.parseInt(cooked[2]);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001134 final String diskId = TextUtils.nullIfEmpty(cooked[3]);
1135 final String partGuid = TextUtils.nullIfEmpty(cooked[4]);
1136
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001137 final DiskInfo disk = mDisks.get(diskId);
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07001138 final VolumeInfo vol = new VolumeInfo(id, type, disk, partGuid);
Jeff Sharkey48877892015-03-18 11:27:19 -07001139 mVolumes.put(id, vol);
1140 onVolumeCreatedLocked(vol);
1141 break;
1142 }
1143 case VoldResponseCode.VOLUME_STATE_CHANGED: {
1144 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001145 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001146 if (vol != null) {
1147 final int oldState = vol.state;
1148 final int newState = Integer.parseInt(cooked[2]);
1149 vol.state = newState;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001150 onVolumeStateChangedLocked(vol, oldState, newState);
Jeff Sharkey48877892015-03-18 11:27:19 -07001151 }
1152 break;
1153 }
1154 case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: {
1155 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001156 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001157 if (vol != null) {
1158 vol.fsType = cooked[2];
1159 }
1160 break;
1161 }
1162 case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
1163 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001164 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001165 if (vol != null) {
1166 vol.fsUuid = cooked[2];
1167 }
1168 break;
1169 }
1170 case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001171 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001172 if (vol != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001173 final StringBuilder builder = new StringBuilder();
1174 for (int i = 2; i < cooked.length; i++) {
1175 builder.append(cooked[i]).append(' ');
1176 }
1177 vol.fsLabel = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001178 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001179 // TODO: notify listeners that label changed
Jeff Sharkey48877892015-03-18 11:27:19 -07001180 break;
1181 }
1182 case VoldResponseCode.VOLUME_PATH_CHANGED: {
1183 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001184 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001185 if (vol != null) {
1186 vol.path = cooked[2];
1187 }
1188 break;
1189 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001190 case VoldResponseCode.VOLUME_INTERNAL_PATH_CHANGED: {
1191 if (cooked.length != 3) break;
1192 final VolumeInfo vol = mVolumes.get(cooked[1]);
1193 if (vol != null) {
1194 vol.internalPath = cooked[2];
1195 }
1196 break;
1197 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001198 case VoldResponseCode.VOLUME_DESTROYED: {
1199 if (cooked.length != 2) break;
1200 mVolumes.remove(cooked[1]);
1201 break;
1202 }
San Mehat4270e1e2010-01-29 05:32:19 -08001203
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001204 case VoldResponseCode.MOVE_STATUS: {
1205 final int status = Integer.parseInt(cooked[1]);
1206 onMoveStatusLocked(status);
1207 break;
1208 }
Jeff Sharkey9756d752015-05-14 21:07:42 -07001209 case VoldResponseCode.BENCHMARK_RESULT: {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001210 if (cooked.length != 7) break;
1211 final String path = cooked[1];
1212 final String ident = cooked[2];
1213 final long create = Long.parseLong(cooked[3]);
1214 final long drop = Long.parseLong(cooked[4]);
1215 final long run = Long.parseLong(cooked[5]);
1216 final long destroy = Long.parseLong(cooked[6]);
1217
Jeff Sharkey9756d752015-05-14 21:07:42 -07001218 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001219 dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
1220 + " " + ident + " " + create + " " + run + " " + destroy);
1221
1222 final VolumeRecord rec = findRecordForPath(path);
1223 if (rec != null) {
1224 rec.lastBenchMillis = System.currentTimeMillis();
1225 writeSettingsLocked();
1226 }
1227
1228 break;
1229 }
1230 case VoldResponseCode.TRIM_RESULT: {
1231 if (cooked.length != 4) break;
1232 final String path = cooked[1];
1233 final long bytes = Long.parseLong(cooked[2]);
1234 final long time = Long.parseLong(cooked[3]);
1235
1236 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
1237 dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path)
1238 + " " + bytes + " " + time);
1239
1240 final VolumeRecord rec = findRecordForPath(path);
1241 if (rec != null) {
1242 rec.lastTrimMillis = System.currentTimeMillis();
1243 writeSettingsLocked();
1244 }
1245
Jeff Sharkey9756d752015-05-14 21:07:42 -07001246 break;
1247 }
1248
Jeff Sharkey48877892015-03-18 11:27:19 -07001249 default: {
1250 Slog.d(TAG, "Unhandled vold event " + code);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001251 }
San Mehat4270e1e2010-01-29 05:32:19 -08001252 }
1253
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001254 return true;
San Mehat4270e1e2010-01-29 05:32:19 -08001255 }
1256
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001257 private void onDiskScannedLocked(DiskInfo disk) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001258 int volumeCount = 0;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001259 for (int i = 0; i < mVolumes.size(); i++) {
1260 final VolumeInfo vol = mVolumes.valueAt(i);
1261 if (Objects.equals(disk.id, vol.getDiskId())) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001262 volumeCount++;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001263 }
1264 }
1265
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001266 final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
Jeff Sharkey7732e1e2016-03-30 17:14:23 -06001267 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1268 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001269 intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
1270 intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001271 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001272
1273 final CountDownLatch latch = mDiskScanLatches.remove(disk.id);
1274 if (latch != null) {
1275 latch.countDown();
1276 }
1277
Jeff Sharkeyf5a6bd72015-05-19 14:42:38 -07001278 disk.volumeCount = volumeCount;
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001279 mCallbacks.notifyDiskScanned(disk, volumeCount);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001280 }
1281
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001282 private void onVolumeCreatedLocked(VolumeInfo vol) {
Jeff Sharkey6855c482016-03-31 14:34:38 -06001283 if (mPms.isOnlyCoreApps()) {
1284 Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId());
1285 return;
1286 }
1287
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001288 if (vol.type == VolumeInfo.TYPE_EMULATED) {
1289 final StorageManager storage = mContext.getSystemService(StorageManager.class);
1290 final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
1291
1292 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
1293 && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
1294 Slog.v(TAG, "Found primary storage at " + vol);
1295 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1296 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1297 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1298
1299 } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
1300 Slog.v(TAG, "Found primary storage at " + vol);
1301 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1302 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1303 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1304 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001305
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001306 } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001307 // TODO: only look at first public partition
1308 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1309 && vol.disk.isDefaultPrimary()) {
1310 Slog.v(TAG, "Found primary storage at " + vol);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001311 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1312 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
San Mehat4270e1e2010-01-29 05:32:19 -08001313 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001314
1315 // Adoptable public disks are visible to apps, since they meet
1316 // public API requirement of being in a stable location.
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001317 if (vol.disk.isAdoptable()) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001318 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1319 }
1320
Jeff Sharkeyab15c392016-05-05 11:45:01 -06001321 vol.mountUserId = mCurrentUserId;
Jeff Sharkey48877892015-03-18 11:27:19 -07001322 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001323
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001324 } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1325 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1326
San Mehat4270e1e2010-01-29 05:32:19 -08001327 } else {
Jeff Sharkey48877892015-03-18 11:27:19 -07001328 Slog.d(TAG, "Skipping automatic mounting of " + vol);
San Mehat4270e1e2010-01-29 05:32:19 -08001329 }
1330 }
1331
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001332 private boolean isBroadcastWorthy(VolumeInfo vol) {
1333 switch (vol.getType()) {
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001334 case VolumeInfo.TYPE_PRIVATE:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001335 case VolumeInfo.TYPE_PUBLIC:
1336 case VolumeInfo.TYPE_EMULATED:
1337 break;
1338 default:
1339 return false;
1340 }
1341
1342 switch (vol.getState()) {
1343 case VolumeInfo.STATE_MOUNTED:
1344 case VolumeInfo.STATE_MOUNTED_READ_ONLY:
1345 case VolumeInfo.STATE_EJECTING:
1346 case VolumeInfo.STATE_UNMOUNTED:
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001347 case VolumeInfo.STATE_UNMOUNTABLE:
Tony Mantlerf0d71052015-06-24 11:45:25 -07001348 case VolumeInfo.STATE_BAD_REMOVAL:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001349 break;
1350 default:
1351 return false;
1352 }
1353
1354 return true;
1355 }
1356
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001357 private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001358 // Remember that we saw this volume so we're ready to accept user
1359 // metadata, or so we can annoy them when a private volume is ejected
1360 if (vol.isMountedReadable() && !TextUtils.isEmpty(vol.fsUuid)) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001361 VolumeRecord rec = mRecords.get(vol.fsUuid);
1362 if (rec == null) {
1363 rec = new VolumeRecord(vol.type, vol.fsUuid);
1364 rec.partGuid = vol.partGuid;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001365 rec.createdMillis = System.currentTimeMillis();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001366 if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1367 rec.nickname = vol.disk.getDescription();
1368 }
1369 mRecords.put(rec.fsUuid, rec);
1370 writeSettingsLocked();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001371 } else {
1372 // Handle upgrade case where we didn't store partition GUID
1373 if (TextUtils.isEmpty(rec.partGuid)) {
1374 rec.partGuid = vol.partGuid;
1375 writeSettingsLocked();
1376 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001377 }
1378 }
1379
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001380 mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
1381
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001382 // Do not broadcast before boot has completed to avoid launching the
1383 // processes that receive the intent unnecessarily.
1384 if (mBootCompleted && isBroadcastWorthy(vol)) {
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001385 final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001386 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
1387 intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
Tony Mantlerf0d71052015-06-24 11:45:25 -07001388 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
Jeff Sharkey7732e1e2016-03-30 17:14:23 -06001389 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1390 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001391 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001392 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001393
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001394 final String oldStateEnv = VolumeInfo.getEnvironmentForState(oldState);
1395 final String newStateEnv = VolumeInfo.getEnvironmentForState(newState);
Emily Bernier92aa5a22014-07-07 10:11:48 -04001396
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001397 if (!Objects.equals(oldStateEnv, newStateEnv)) {
1398 // Kick state changed event towards all started users. Any users
1399 // started after this point will trigger additional
1400 // user-specific broadcasts.
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001401 for (int userId : mSystemUnlockedUsers) {
Jeff Sharkey46349872015-07-28 10:49:47 -07001402 if (vol.isVisibleForRead(userId)) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001403 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001404 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey48877892015-03-18 11:27:19 -07001405
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001406 mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
1407 newStateEnv);
San Mehat4270e1e2010-01-29 05:32:19 -08001408 }
1409 }
1410 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001411
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001412 if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.state == VolumeInfo.STATE_EJECTING) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001413 // TODO: this should eventually be handled by new ObbVolume state changes
1414 /*
1415 * Some OBBs might have been unmounted when this volume was
1416 * unmounted, so send a message to the handler to let it know to
1417 * remove those from the list of mounted OBBS.
1418 */
1419 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
1420 OBB_FLUSH_MOUNT_STATE, vol.path));
1421 }
San Mehat4270e1e2010-01-29 05:32:19 -08001422 }
1423
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001424 private void onMoveStatusLocked(int status) {
1425 if (mMoveCallback == null) {
1426 Slog.w(TAG, "Odd, status but no move requested");
1427 return;
1428 }
1429
1430 // TODO: estimate remaining time
1431 try {
Jeff Sharkey50a05452015-04-29 11:24:52 -07001432 mMoveCallback.onStatusChanged(-1, status, -1);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001433 } catch (RemoteException ignored) {
1434 }
1435
1436 // We've finished copying and we're about to clean up old data, so
1437 // remember that move was successful if we get rebooted
1438 if (status == MOVE_STATUS_COPY_FINISHED) {
1439 Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
1440
1441 mPrimaryStorageUuid = mMoveTargetUuid;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001442 writeSettingsLocked();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001443 }
1444
1445 if (PackageManager.isMoveStatusFinished(status)) {
1446 Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status);
1447
1448 mMoveCallback = null;
1449 mMoveTargetUuid = null;
1450 }
1451 }
1452
Jeff Sharkey48877892015-03-18 11:27:19 -07001453 private void enforcePermission(String perm) {
1454 mContext.enforceCallingOrSelfPermission(perm, perm);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001455 }
1456
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001457 /**
1458 * Decide if volume is mountable per device policies.
1459 */
1460 private boolean isMountDisallowed(VolumeInfo vol) {
Philip P. Moltmannec3cbb22016-09-14 13:24:52 -07001461 UserManager userManager = mContext.getSystemService(UserManager.class);
1462
1463 boolean isUsbRestricted = false;
1464 if (vol.disk != null && vol.disk.isUsb()) {
1465 isUsbRestricted = userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER,
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001466 Binder.getCallingUserHandle());
Emily Bernier92aa5a22014-07-07 10:11:48 -04001467 }
Philip P. Moltmannec3cbb22016-09-14 13:24:52 -07001468
1469 boolean isTypeRestricted = false;
1470 if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
1471 isTypeRestricted = userManager
1472 .hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
1473 Binder.getCallingUserHandle());
1474 }
1475
1476 return isUsbRestricted || isTypeRestricted;
Emily Bernier92aa5a22014-07-07 10:11:48 -04001477 }
1478
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001479 private void enforceAdminUser() {
1480 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1481 final int callingUserId = UserHandle.getCallingUserId();
1482 boolean isAdmin;
1483 long token = Binder.clearCallingIdentity();
1484 try {
1485 isAdmin = um.getUserInfo(callingUserId).isAdmin();
1486 } finally {
1487 Binder.restoreCallingIdentity(token);
1488 }
1489 if (!isAdmin) {
1490 throw new SecurityException("Only admin users can adopt sd cards");
1491 }
1492 }
1493
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001494 /**
Sudheer Shanka2250d562016-11-07 15:41:02 -08001495 * Constructs a new StorageManagerService instance
San Mehat207e5382010-02-04 20:46:54 -08001496 *
1497 * @param context Binder context for this service
1498 */
Sudheer Shanka2250d562016-11-07 15:41:02 -08001499 public StorageManagerService(Context context) {
Christopher Tated417d622013-08-19 16:14:25 -07001500 sSelf = this;
1501
San Mehat207e5382010-02-04 20:46:54 -08001502 mContext = context;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001503 mCallbacks = new Callbacks(FgThread.get().getLooper());
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001504 mLockPatternUtils = new LockPatternUtils(mContext);
San Mehat207e5382010-02-04 20:46:54 -08001505
San Mehat207e5382010-02-04 20:46:54 -08001506 // XXX: This will go away soon in favor of IMountServiceObserver
1507 mPms = (PackageManagerService) ServiceManager.getService("package");
1508
Dianne Hackbornefa92b22013-05-03 14:11:43 -07001509 HandlerThread hthread = new HandlerThread(TAG);
1510 hthread.start();
Sudheer Shanka2250d562016-11-07 15:41:02 -08001511 mHandler = new StorageManagerServiceHandler(hthread.getLooper());
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001512
Sudheer Shanka2250d562016-11-07 15:41:02 -08001513 // Add OBB Action Handler to StorageManagerService thread.
Dianne Hackborn8d044e82013-04-30 17:24:15 -07001514 mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
Kenny Roota02b8b02010-08-05 16:14:17 -07001515
Christopher Tate7265abe2014-11-21 13:54:45 -08001516 // Initialize the last-fstrim tracking if necessary
1517 File dataDir = Environment.getDataDirectory();
1518 File systemDir = new File(dataDir, "system");
1519 mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
1520 if (!mLastMaintenanceFile.exists()) {
1521 // Not setting mLastMaintenance here means that we will force an
1522 // fstrim during reboot following the OTA that installs this code.
1523 try {
1524 (new FileOutputStream(mLastMaintenanceFile)).close();
1525 } catch (IOException e) {
1526 Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
1527 }
1528 } else {
1529 mLastMaintenance = mLastMaintenanceFile.lastModified();
1530 }
1531
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001532 mSettingsFile = new AtomicFile(
Jeff Sharkey8212ae02016-02-10 14:46:43 -07001533 new File(Environment.getDataSystemDirectory(), "storage.xml"));
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001534
1535 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001536 readSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001537 }
1538
Sudheer Shanka2250d562016-11-07 15:41:02 -08001539 LocalServices.addService(StorageManagerInternal.class, mStorageManagerInternal);
Svet Ganov6ee871e2015-07-10 14:29:33 -07001540
Marco Nelissenc34ebce2010-02-18 13:39:41 -08001541 /*
Kenny Root305bcbf2010-09-03 07:56:38 -07001542 * Create the connection to vold with a maximum queue of twice the
1543 * amount of containers we'd ever expect to have. This keeps an
1544 * "asec list" from blocking a thread repeatedly.
1545 */
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001546
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001547 mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
1548 null);
Jeff Sharkey48877892015-03-18 11:27:19 -07001549 mConnector.setDebug(true);
Jeff Sharkey8948c012015-11-03 12:33:54 -08001550 mConnector.setWarnIfHeld(mLock);
Jeff Sharkeycd575992016-03-29 14:12:49 -06001551 mConnectorThread = new Thread(mConnector, VOLD_TAG);
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07001552
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001553 // Reuse parameters from first connector since they are tested and safe
1554 mCryptConnector = new NativeDaemonConnector(this, "cryptd",
1555 MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
1556 mCryptConnector.setDebug(true);
Jeff Sharkeycd575992016-03-29 14:12:49 -06001557 mCryptConnectorThread = new Thread(mCryptConnector, CRYPTD_TAG);
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001558
Jeff Sharkeybcd262d2015-06-10 09:41:17 -07001559 final IntentFilter userFilter = new IntentFilter();
1560 userFilter.addAction(Intent.ACTION_USER_ADDED);
1561 userFilter.addAction(Intent.ACTION_USER_REMOVED);
1562 mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
1563
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001564 synchronized (mLock) {
1565 addInternalVolumeLocked();
1566 }
Amith Yamasania7892482015-08-07 11:09:05 -07001567
Kenny Root07714d42011-08-17 17:49:28 -07001568 // Add ourself to the Watchdog monitors if enabled.
1569 if (WATCHDOG_ENABLE) {
1570 Watchdog.getInstance().addMonitor(this);
1571 }
San Mehat207e5382010-02-04 20:46:54 -08001572 }
1573
Jeff Sharkeycd575992016-03-29 14:12:49 -06001574 private void start() {
1575 mConnectorThread.start();
1576 mCryptConnectorThread.start();
1577 }
1578
Jeff Sharkey56e62932015-03-21 20:41:00 -07001579 private void systemReady() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001580 mSystemReady = true;
1581 mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
1582 }
1583
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001584 private void bootCompleted() {
1585 mBootCompleted = true;
1586 }
1587
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001588 private String getDefaultPrimaryStorageUuid() {
1589 if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) {
1590 return StorageManager.UUID_PRIMARY_PHYSICAL;
1591 } else {
1592 return StorageManager.UUID_PRIVATE_INTERNAL;
1593 }
1594 }
1595
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001596 private void readSettingsLocked() {
1597 mRecords.clear();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001598 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001599 mForceAdoptable = false;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001600
1601 FileInputStream fis = null;
1602 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001603 fis = mSettingsFile.openRead();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001604 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001605 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001606
1607 int type;
1608 while ((type = in.next()) != END_DOCUMENT) {
1609 if (type == START_TAG) {
1610 final String tag = in.getName();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001611 if (TAG_VOLUMES.equals(tag)) {
1612 final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001613 final boolean primaryPhysical = SystemProperties.getBoolean(
1614 StorageManager.PROP_PRIMARY_PHYSICAL, false);
1615 final boolean validAttr = (version >= VERSION_FIX_PRIMARY)
1616 || (version >= VERSION_ADD_PRIMARY && !primaryPhysical);
1617 if (validAttr) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001618 mPrimaryStorageUuid = readStringAttribute(in,
1619 ATTR_PRIMARY_STORAGE_UUID);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001620 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001621 mForceAdoptable = readBooleanAttribute(in, ATTR_FORCE_ADOPTABLE, false);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001622
1623 } else if (TAG_VOLUME.equals(tag)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001624 final VolumeRecord rec = readVolumeRecord(in);
1625 mRecords.put(rec.fsUuid, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001626 }
1627 }
1628 }
1629 } catch (FileNotFoundException e) {
1630 // Missing metadata is okay, probably first boot
1631 } catch (IOException e) {
1632 Slog.wtf(TAG, "Failed reading metadata", e);
1633 } catch (XmlPullParserException e) {
1634 Slog.wtf(TAG, "Failed reading metadata", e);
1635 } finally {
1636 IoUtils.closeQuietly(fis);
1637 }
1638 }
1639
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001640 private void writeSettingsLocked() {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001641 FileOutputStream fos = null;
1642 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001643 fos = mSettingsFile.startWrite();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001644
1645 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001646 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001647 out.startDocument(null, true);
1648 out.startTag(null, TAG_VOLUMES);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001649 writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001650 writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001651 writeBooleanAttribute(out, ATTR_FORCE_ADOPTABLE, mForceAdoptable);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001652 final int size = mRecords.size();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001653 for (int i = 0; i < size; i++) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001654 final VolumeRecord rec = mRecords.valueAt(i);
1655 writeVolumeRecord(out, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001656 }
1657 out.endTag(null, TAG_VOLUMES);
1658 out.endDocument();
1659
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001660 mSettingsFile.finishWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001661 } catch (IOException e) {
1662 if (fos != null) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001663 mSettingsFile.failWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001664 }
1665 }
1666 }
1667
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001668 public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
1669 final int type = readIntAttribute(in, ATTR_TYPE);
1670 final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
1671 final VolumeRecord meta = new VolumeRecord(type, fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001672 meta.partGuid = readStringAttribute(in, ATTR_PART_GUID);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001673 meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
1674 meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001675 meta.createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
1676 meta.lastTrimMillis = readLongAttribute(in, ATTR_LAST_TRIM_MILLIS);
1677 meta.lastBenchMillis = readLongAttribute(in, ATTR_LAST_BENCH_MILLIS);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001678 return meta;
1679 }
1680
1681 public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
1682 out.startTag(null, TAG_VOLUME);
1683 writeIntAttribute(out, ATTR_TYPE, rec.type);
1684 writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001685 writeStringAttribute(out, ATTR_PART_GUID, rec.partGuid);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001686 writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
1687 writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001688 writeLongAttribute(out, ATTR_CREATED_MILLIS, rec.createdMillis);
1689 writeLongAttribute(out, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
1690 writeLongAttribute(out, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001691 out.endTag(null, TAG_VOLUME);
1692 }
1693
San Mehat207e5382010-02-04 20:46:54 -08001694 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001695 * Exposed API calls below here
1696 */
1697
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001698 @Override
Sudheer Shanka2250d562016-11-07 15:41:02 -08001699 public void registerListener(IStorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001700 mCallbacks.register(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001701 }
1702
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001703 @Override
Sudheer Shanka2250d562016-11-07 15:41:02 -08001704 public void unregisterListener(IStorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001705 mCallbacks.unregister(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001706 }
1707
Jeff Sharkey48877892015-03-18 11:27:19 -07001708 @Override
Sudheer Shanka2250d562016-11-07 15:41:02 -08001709 public void shutdown(final IStorageShutdownObserver observer) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001710 enforcePermission(android.Manifest.permission.SHUTDOWN);
San Mehat4270e1e2010-01-29 05:32:19 -08001711
San Mehata5078592010-03-25 09:36:54 -07001712 Slog.i(TAG, "Shutting down");
Jeff Sharkey48877892015-03-18 11:27:19 -07001713 mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001714 }
1715
Jeff Sharkey48877892015-03-18 11:27:19 -07001716 @Override
San Mehatb1043402010-02-05 08:26:50 -08001717 public boolean isUsbMassStorageConnected() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001718 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001719 }
1720
Jeff Sharkey48877892015-03-18 11:27:19 -07001721 @Override
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -08001722 public void setUsbMassStorageEnabled(boolean enable) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001723 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001724 }
1725
Jeff Sharkey48877892015-03-18 11:27:19 -07001726 @Override
San Mehatb1043402010-02-05 08:26:50 -08001727 public boolean isUsbMassStorageEnabled() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001728 throw new UnsupportedOperationException();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 }
Jason parks9ed98bc2011-01-17 09:58:35 -06001730
Jeff Sharkey48877892015-03-18 11:27:19 -07001731 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001732 public String getVolumeState(String mountPoint) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001733 throw new UnsupportedOperationException();
San Mehat7fd0fee2009-12-17 07:12:23 -08001734 }
1735
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001736 @Override
Kenny Roote1ff2142010-10-12 11:20:01 -07001737 public boolean isExternalStorageEmulated() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001738 throw new UnsupportedOperationException();
Kenny Roote1ff2142010-10-12 11:20:01 -07001739 }
1740
Jeff Sharkey48877892015-03-18 11:27:19 -07001741 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001742 public int mountVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001743 mount(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001744 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001745 }
1746
Jeff Sharkey48877892015-03-18 11:27:19 -07001747 @Override
Ben Komalo13c71972011-09-07 16:35:56 -07001748 public void unmountVolume(String path, boolean force, boolean removeEncryption) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001749 unmount(findVolumeIdForPathOrThrow(path));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 }
1751
Jeff Sharkey48877892015-03-18 11:27:19 -07001752 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001753 public int formatVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001754 format(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001755 return 0;
1756 }
1757
1758 @Override
1759 public void mount(String volId) {
1760 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1761 waitForReady();
1762
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001763 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001764 if (isMountDisallowed(vol)) {
1765 throw new SecurityException("Mounting " + volId + " restricted by policy");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001766 }
1767 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001768 mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001769 } catch (NativeDaemonConnectorException e) {
1770 throw e.rethrowAsParcelableException();
1771 }
1772 }
1773
1774 @Override
1775 public void unmount(String volId) {
1776 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1777 waitForReady();
1778
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001779 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001780
1781 // TODO: expand PMS to know about multiple volumes
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001782 if (vol.isPrimaryPhysical()) {
1783 final long ident = Binder.clearCallingIdentity();
1784 try {
1785 synchronized (mUnmountLock) {
1786 mUnmountSignal = new CountDownLatch(1);
1787 mPms.updateExternalMediaStatus(false, true);
1788 waitForLatch(mUnmountSignal, "mUnmountSignal");
1789 mUnmountSignal = null;
1790 }
1791 } finally {
1792 Binder.restoreCallingIdentity(ident);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001793 }
1794 }
1795
1796 try {
1797 mConnector.execute("volume", "unmount", vol.id);
1798 } catch (NativeDaemonConnectorException e) {
1799 throw e.rethrowAsParcelableException();
1800 }
1801 }
1802
1803 @Override
1804 public void format(String volId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001805 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -08001806 waitForReady();
San Mehat5b77dab2010-01-26 13:28:50 -08001807
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001808 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001809 try {
Jeff Sharkey4e83cc92015-05-27 14:38:39 -07001810 mConnector.execute("volume", "format", vol.id, "auto");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001811 } catch (NativeDaemonConnectorException e) {
1812 throw e.rethrowAsParcelableException();
Jeff Sharkey48877892015-03-18 11:27:19 -07001813 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001814 }
1815
1816 @Override
Jeff Sharkey9756d752015-05-14 21:07:42 -07001817 public long benchmark(String volId) {
1818 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1819 waitForReady();
1820
1821 try {
Jeff Sharkey14cbe522015-07-08 14:06:37 -07001822 // TODO: make benchmark async so we don't block other commands
1823 final NativeDaemonEvent res = mConnector.execute(3 * DateUtils.MINUTE_IN_MILLIS,
1824 "volume", "benchmark", volId);
Jeff Sharkey9756d752015-05-14 21:07:42 -07001825 return Long.parseLong(res.getMessage());
Todd Kennedy8101ee62015-06-23 13:35:28 -07001826 } catch (NativeDaemonTimeoutException e) {
1827 return Long.MAX_VALUE;
Jeff Sharkey9756d752015-05-14 21:07:42 -07001828 } catch (NativeDaemonConnectorException e) {
1829 throw e.rethrowAsParcelableException();
1830 }
1831 }
1832
1833 @Override
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001834 public void partitionPublic(String diskId) {
1835 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1836 waitForReady();
1837
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001838 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001839 try {
1840 mConnector.execute("volume", "partition", diskId, "public");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001841 waitForLatch(latch, "partitionPublic", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001842 } catch (NativeDaemonConnectorException e) {
1843 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001844 } catch (TimeoutException e) {
1845 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001846 }
1847 }
1848
1849 @Override
1850 public void partitionPrivate(String diskId) {
1851 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001852 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001853 waitForReady();
1854
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001855 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001856 try {
1857 mConnector.execute("volume", "partition", diskId, "private");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001858 waitForLatch(latch, "partitionPrivate", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001859 } catch (NativeDaemonConnectorException e) {
1860 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001861 } catch (TimeoutException e) {
1862 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001863 }
1864 }
1865
1866 @Override
1867 public void partitionMixed(String diskId, int ratio) {
1868 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001869 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001870 waitForReady();
1871
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001872 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001873 try {
1874 mConnector.execute("volume", "partition", diskId, "mixed", ratio);
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001875 waitForLatch(latch, "partitionMixed", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001876 } catch (NativeDaemonConnectorException e) {
1877 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001878 } catch (TimeoutException e) {
1879 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001880 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001881 }
1882
Jeff Sharkey48877892015-03-18 11:27:19 -07001883 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001884 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001885 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1886 waitForReady();
1887
Jeff Sharkey50a05452015-04-29 11:24:52 -07001888 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001889 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001890 final VolumeRecord rec = mRecords.get(fsUuid);
1891 rec.nickname = nickname;
Jeff Sharkey50a05452015-04-29 11:24:52 -07001892 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001893 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001894 }
1895 }
1896
1897 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001898 public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001899 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1900 waitForReady();
1901
Jeff Sharkey50a05452015-04-29 11:24:52 -07001902 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001903 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001904 final VolumeRecord rec = mRecords.get(fsUuid);
1905 rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001906 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001907 writeSettingsLocked();
1908 }
1909 }
1910
1911 @Override
1912 public void forgetVolume(String fsUuid) {
1913 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1914 waitForReady();
1915
Jeff Sharkey50a05452015-04-29 11:24:52 -07001916 Preconditions.checkNotNull(fsUuid);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001917
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001918 synchronized (mLock) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001919 final VolumeRecord rec = mRecords.remove(fsUuid);
1920 if (rec != null && !TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001921 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001922 }
1923 mCallbacks.notifyVolumeForgotten(fsUuid);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001924
1925 // If this had been primary storage, revert back to internal and
1926 // reset vold so we bind into new volume into place.
1927 if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001928 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001929 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001930 }
1931
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001932 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001933 }
1934 }
1935
Jeff Sharkey7d2af542015-05-12 15:27:15 -07001936 @Override
1937 public void forgetAllVolumes() {
1938 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1939 waitForReady();
1940
Jeff Sharkey50a05452015-04-29 11:24:52 -07001941 synchronized (mLock) {
1942 for (int i = 0; i < mRecords.size(); i++) {
1943 final String fsUuid = mRecords.keyAt(i);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001944 final VolumeRecord rec = mRecords.valueAt(i);
1945 if (!TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001946 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001947 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001948 mCallbacks.notifyVolumeForgotten(fsUuid);
1949 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001950 mRecords.clear();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001951
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001952 if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)) {
1953 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
1954 }
1955
1956 writeSettingsLocked();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001957 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001958 }
1959 }
1960
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001961 private void forgetPartition(String partGuid) {
1962 try {
1963 mConnector.execute("volume", "forget_partition", partGuid);
1964 } catch (NativeDaemonConnectorException e) {
1965 Slog.w(TAG, "Failed to forget key for " + partGuid + ": " + e);
1966 }
1967 }
1968
Jeff Sharkey31d0b702016-11-21 14:16:53 -07001969 @Override
1970 public void fstrim(int flags) {
1971 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1972 waitForReady();
1973
1974 String cmd;
1975 if ((flags & StorageManager.FSTRIM_FLAG_DEEP) != 0) {
1976 cmd = "dodtrim";
1977 } else {
1978 cmd = "dotrim";
1979 }
1980 if ((flags & StorageManager.FSTRIM_FLAG_BENCHMARK) != 0) {
1981 cmd += "bench";
1982 }
1983
1984 try {
1985 mConnector.execute("fstrim", cmd);
1986 } catch (NativeDaemonConnectorException e) {
1987 Slog.e(TAG, "Failed to run fstrim: " + e);
1988 }
1989 }
1990
Svet Ganov6ee871e2015-07-10 14:29:33 -07001991 private void remountUidExternalStorage(int uid, int mode) {
Jeff Sharkey9527b222015-06-24 15:24:48 -07001992 waitForReady();
1993
Svet Ganov6ee871e2015-07-10 14:29:33 -07001994 String modeName = "none";
1995 switch (mode) {
1996 case Zygote.MOUNT_EXTERNAL_DEFAULT: {
1997 modeName = "default";
1998 } break;
1999
2000 case Zygote.MOUNT_EXTERNAL_READ: {
2001 modeName = "read";
2002 } break;
2003
2004 case Zygote.MOUNT_EXTERNAL_WRITE: {
2005 modeName = "write";
2006 } break;
Jeff Sharkey9527b222015-06-24 15:24:48 -07002007 }
2008
2009 try {
Svet Ganov6ee871e2015-07-10 14:29:33 -07002010 mConnector.execute("volume", "remount_uid", uid, modeName);
Jeff Sharkey9527b222015-06-24 15:24:48 -07002011 } catch (NativeDaemonConnectorException e) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07002012 Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e);
Jeff Sharkey9527b222015-06-24 15:24:48 -07002013 }
2014 }
2015
2016 @Override
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002017 public void setDebugFlags(int flags, int mask) {
2018 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2019 waitForReady();
2020
Jeff Sharkeyba512352015-11-12 20:17:45 -08002021 if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
Jeff Sharkey00455bf2016-11-04 14:45:24 -06002022 if (!EMULATE_FBE_SUPPORTED) {
2023 throw new IllegalStateException(
2024 "Emulation not supported on this device");
2025 }
Paul Lawrence20be5d62016-02-26 13:51:17 -08002026 if (StorageManager.isFileEncryptedNativeOnly()) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002027 throw new IllegalStateException(
Jeff Sharkey00455bf2016-11-04 14:45:24 -06002028 "Emulation not supported on device with native FBE");
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002029 }
Jeff Sharkey5a785162016-03-21 13:02:06 -06002030 if (mLockPatternUtils.isCredentialRequiredToDecrypt(false)) {
2031 throw new IllegalStateException(
2032 "Emulation requires disabling 'Secure start-up' in Settings > Security");
2033 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002034
Jeff Sharkey1176e512016-02-29 17:01:26 -07002035 final long token = Binder.clearCallingIdentity();
2036 try {
2037 final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
2038 SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002039
Jeff Sharkey1176e512016-02-29 17:01:26 -07002040 // Perform hard reboot to kick policy into place
2041 mContext.getSystemService(PowerManager.class).reboot(null);
2042 } finally {
2043 Binder.restoreCallingIdentity(token);
2044 }
Jeff Sharkeyba512352015-11-12 20:17:45 -08002045 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002046
Jeff Sharkeyba512352015-11-12 20:17:45 -08002047 if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
Jeff Sharkey6ed74182016-08-23 13:53:53 -06002048 if (StorageManager.isFileEncryptedNativeOnly()) {
2049 throw new IllegalStateException(
2050 "Adoptable storage not available on device with native FBE");
2051 }
2052
Jeff Sharkeyba512352015-11-12 20:17:45 -08002053 synchronized (mLock) {
2054 mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
2055
2056 writeSettingsLocked();
2057 mHandler.obtainMessage(H_RESET).sendToTarget();
2058 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002059 }
Jeff Sharkey33dd1562016-04-07 11:05:33 -06002060
2061 if ((mask & (StorageManager.DEBUG_SDCARDFS_FORCE_ON
2062 | StorageManager.DEBUG_SDCARDFS_FORCE_OFF)) != 0) {
2063 final String value;
2064 if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_ON) != 0) {
2065 value = "force_on";
2066 } else if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_OFF) != 0) {
2067 value = "force_off";
2068 } else {
2069 value = "";
2070 }
2071
2072 final long token = Binder.clearCallingIdentity();
2073 try {
2074 SystemProperties.set(StorageManager.PROP_SDCARDFS, value);
2075
2076 // Reset storage to kick new setting into place
2077 mHandler.obtainMessage(H_RESET).sendToTarget();
2078 } finally {
2079 Binder.restoreCallingIdentity(token);
2080 }
2081 }
Jeff Sharkeye53e2d92017-03-25 23:14:06 -06002082
2083 if ((mask & StorageManager.DEBUG_VIRTUAL_DISK) != 0) {
2084 final boolean enabled = (flags & StorageManager.DEBUG_VIRTUAL_DISK) != 0;
2085
2086 final long token = Binder.clearCallingIdentity();
2087 try {
2088 SystemProperties.set(StorageManager.PROP_VIRTUAL_DISK, Boolean.toString(enabled));
2089
2090 // Reset storage to kick new setting into place
2091 mHandler.obtainMessage(H_RESET).sendToTarget();
2092 } finally {
2093 Binder.restoreCallingIdentity(token);
2094 }
2095 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002096 }
2097
2098 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002099 public String getPrimaryStorageUuid() {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002100 synchronized (mLock) {
2101 return mPrimaryStorageUuid;
2102 }
2103 }
2104
2105 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002106 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
2107 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2108 waitForReady();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002109
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002110 final VolumeInfo from;
2111 final VolumeInfo to;
2112
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002113 synchronized (mLock) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002114 if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) {
2115 throw new IllegalArgumentException("Primary storage already at " + volumeUuid);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002116 }
2117
2118 if (mMoveCallback != null) {
2119 throw new IllegalStateException("Move already in progress");
2120 }
2121 mMoveCallback = callback;
2122 mMoveTargetUuid = volumeUuid;
2123
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002124 // When moving to/from primary physical volume, we probably just nuked
2125 // the current storage location, so we have nothing to move.
2126 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
2127 || Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
2128 Slog.d(TAG, "Skipping move to/from primary physical");
2129 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
2130 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08002131 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002132 return;
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002133
2134 } else {
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002135 from = findStorageForUuid(mPrimaryStorageUuid);
2136 to = findStorageForUuid(volumeUuid);
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07002137
2138 if (from == null) {
2139 Slog.w(TAG, "Failing move due to missing from volume " + mPrimaryStorageUuid);
2140 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2141 return;
2142 } else if (to == null) {
2143 Slog.w(TAG, "Failing move due to missing to volume " + volumeUuid);
2144 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2145 return;
2146 }
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002147 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002148 }
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002149
2150 try {
2151 mConnector.execute("volume", "move_storage", from.id, to.id);
2152 } catch (NativeDaemonConnectorException e) {
2153 throw e.rethrowAsParcelableException();
2154 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002155 }
2156
2157 @Override
Mike Lockwoodecedfdc2011-06-08 15:11:59 -07002158 public int[] getStorageUsers(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002159 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehatc1b4ce92010-02-16 17:13:03 -08002160 waitForReady();
2161 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002162 final String[] r = NativeDaemonEvent.filterMessageList(
2163 mConnector.executeForList("storage", "users", path),
2164 VoldResponseCode.StorageUsersListResult);
2165
San Mehatc1b4ce92010-02-16 17:13:03 -08002166 // FMT: <pid> <process name>
2167 int[] data = new int[r.length];
2168 for (int i = 0; i < r.length; i++) {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002169 String[] tok = r[i].split(" ");
San Mehatc1b4ce92010-02-16 17:13:03 -08002170 try {
2171 data[i] = Integer.parseInt(tok[0]);
2172 } catch (NumberFormatException nfe) {
San Mehata5078592010-03-25 09:36:54 -07002173 Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
San Mehatc1b4ce92010-02-16 17:13:03 -08002174 return new int[0];
2175 }
2176 }
2177 return data;
2178 } catch (NativeDaemonConnectorException e) {
San Mehata5078592010-03-25 09:36:54 -07002179 Slog.e(TAG, "Failed to retrieve storage users list", e);
San Mehatc1b4ce92010-02-16 17:13:03 -08002180 return new int[0];
2181 }
2182 }
2183
San Mehatb1043402010-02-05 08:26:50 -08002184 private void warnOnNotMounted() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002185 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002186 for (int i = 0; i < mVolumes.size(); i++) {
2187 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07002188 if (vol.isPrimary() && vol.isMountedWritable()) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002189 // Cool beans, we have a mounted primary volume
2190 return;
2191 }
Jeff Sharkey32ee8312012-09-30 13:21:31 -07002192 }
San Mehatb1043402010-02-05 08:26:50 -08002193 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002194
2195 Slog.w(TAG, "No primary storage mounted!");
San Mehatb1043402010-02-05 08:26:50 -08002196 }
2197
San Mehat4270e1e2010-01-29 05:32:19 -08002198 public String[] getSecureContainerList() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002199 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002200 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002201 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002202
San Mehat4270e1e2010-01-29 05:32:19 -08002203 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002204 return NativeDaemonEvent.filterMessageList(
2205 mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
San Mehat4270e1e2010-01-29 05:32:19 -08002206 } catch (NativeDaemonConnectorException e) {
2207 return new String[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002208 }
2209 }
San Mehat36972292010-01-06 11:06:32 -08002210
Kenny Root6dceb882012-04-12 14:23:49 -07002211 public int createSecureContainer(String id, int sizeMb, String fstype, String key,
2212 int ownerUid, boolean external) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002213 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehat207e5382010-02-04 20:46:54 -08002214 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002215 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002216
San Mehatb1043402010-02-05 08:26:50 -08002217 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002218 try {
Jeff Sharkey56cd6462013-06-07 15:09:15 -07002219 mConnector.execute("asec", "create", id, sizeMb, fstype, new SensitiveArg(key),
2220 ownerUid, external ? "1" : "0");
San Mehat4270e1e2010-01-29 05:32:19 -08002221 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002222 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002223 }
San Mehata181b212010-02-11 06:50:20 -08002224
2225 if (rc == StorageResultCode.OperationSucceeded) {
2226 synchronized (mAsecMountSet) {
2227 mAsecMountSet.add(id);
2228 }
2229 }
San Mehat4270e1e2010-01-29 05:32:19 -08002230 return rc;
San Mehat36972292010-01-06 11:06:32 -08002231 }
2232
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002233 @Override
2234 public int resizeSecureContainer(String id, int sizeMb, String key) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002235 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002236 waitForReady();
2237 warnOnNotMounted();
2238
2239 int rc = StorageResultCode.OperationSucceeded;
2240 try {
2241 mConnector.execute("asec", "resize", id, sizeMb, new SensitiveArg(key));
2242 } catch (NativeDaemonConnectorException e) {
2243 rc = StorageResultCode.OperationFailedInternalError;
2244 }
2245 return rc;
2246 }
2247
San Mehat4270e1e2010-01-29 05:32:19 -08002248 public int finalizeSecureContainer(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002249 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehatb1043402010-02-05 08:26:50 -08002250 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002251
San Mehatb1043402010-02-05 08:26:50 -08002252 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002253 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002254 mConnector.execute("asec", "finalize", id);
San Mehata181b212010-02-11 06:50:20 -08002255 /*
2256 * Finalization does a remount, so no need
2257 * to update mAsecMountSet
2258 */
San Mehat4270e1e2010-01-29 05:32:19 -08002259 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002260 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002261 }
San Mehat4270e1e2010-01-29 05:32:19 -08002262 return rc;
San Mehat36972292010-01-06 11:06:32 -08002263 }
2264
Kenny Root6dceb882012-04-12 14:23:49 -07002265 public int fixPermissionsSecureContainer(String id, int gid, String filename) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002266 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Kenny Root6dceb882012-04-12 14:23:49 -07002267 warnOnNotMounted();
2268
2269 int rc = StorageResultCode.OperationSucceeded;
2270 try {
2271 mConnector.execute("asec", "fixperms", id, gid, filename);
2272 /*
2273 * Fix permissions does a remount, so no need to update
2274 * mAsecMountSet
2275 */
2276 } catch (NativeDaemonConnectorException e) {
2277 rc = StorageResultCode.OperationFailedInternalError;
2278 }
2279 return rc;
2280 }
2281
San Mehatd9709982010-02-18 11:43:03 -08002282 public int destroySecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002283 enforcePermission(android.Manifest.permission.ASEC_DESTROY);
San Mehat207e5382010-02-04 20:46:54 -08002284 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002285 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002286
Kenny Rootaa485402010-09-14 14:49:41 -07002287 /*
2288 * Force a GC to make sure AssetManagers in other threads of the
2289 * system_server are cleaned up. We have to do this since AssetManager
2290 * instances are kept as a WeakReference and it's possible we have files
2291 * open on the external storage.
2292 */
2293 Runtime.getRuntime().gc();
2294
San Mehatb1043402010-02-05 08:26:50 -08002295 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002296 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002297 final Command cmd = new Command("asec", "destroy", id);
2298 if (force) {
2299 cmd.appendArg("force");
2300 }
2301 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002302 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002303 int code = e.getCode();
2304 if (code == VoldResponseCode.OpFailedStorageBusy) {
2305 rc = StorageResultCode.OperationFailedStorageBusy;
2306 } else {
2307 rc = StorageResultCode.OperationFailedInternalError;
2308 }
San Mehat02735bc2010-01-26 15:18:08 -08002309 }
San Mehata181b212010-02-11 06:50:20 -08002310
2311 if (rc == StorageResultCode.OperationSucceeded) {
2312 synchronized (mAsecMountSet) {
2313 if (mAsecMountSet.contains(id)) {
2314 mAsecMountSet.remove(id);
2315 }
2316 }
2317 }
2318
San Mehat4270e1e2010-01-29 05:32:19 -08002319 return rc;
San Mehat36972292010-01-06 11:06:32 -08002320 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002321
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002322 public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002323 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002324 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002325 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002326
San Mehata181b212010-02-11 06:50:20 -08002327 synchronized (mAsecMountSet) {
2328 if (mAsecMountSet.contains(id)) {
2329 return StorageResultCode.OperationFailedStorageMounted;
2330 }
2331 }
2332
San Mehatb1043402010-02-05 08:26:50 -08002333 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002334 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002335 mConnector.execute("asec", "mount", id, new SensitiveArg(key), ownerUid,
2336 readOnly ? "ro" : "rw");
San Mehat4270e1e2010-01-29 05:32:19 -08002337 } catch (NativeDaemonConnectorException e) {
Kenny Rootf0304622010-03-19 19:20:42 -07002338 int code = e.getCode();
2339 if (code != VoldResponseCode.OpFailedStorageBusy) {
2340 rc = StorageResultCode.OperationFailedInternalError;
2341 }
San Mehat02735bc2010-01-26 15:18:08 -08002342 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002343
2344 if (rc == StorageResultCode.OperationSucceeded) {
2345 synchronized (mAsecMountSet) {
2346 mAsecMountSet.add(id);
2347 }
2348 }
San Mehat4270e1e2010-01-29 05:32:19 -08002349 return rc;
San Mehat36972292010-01-06 11:06:32 -08002350 }
2351
San Mehatd9709982010-02-18 11:43:03 -08002352 public int unmountSecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002353 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002354 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002355 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002356
San Mehat6cdd9c02010-02-09 14:45:20 -08002357 synchronized (mAsecMountSet) {
2358 if (!mAsecMountSet.contains(id)) {
San Mehata181b212010-02-11 06:50:20 -08002359 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehat6cdd9c02010-02-09 14:45:20 -08002360 }
2361 }
2362
Kenny Rootaa485402010-09-14 14:49:41 -07002363 /*
2364 * Force a GC to make sure AssetManagers in other threads of the
2365 * system_server are cleaned up. We have to do this since AssetManager
2366 * instances are kept as a WeakReference and it's possible we have files
2367 * open on the external storage.
2368 */
2369 Runtime.getRuntime().gc();
2370
San Mehatb1043402010-02-05 08:26:50 -08002371 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002372 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002373 final Command cmd = new Command("asec", "unmount", id);
2374 if (force) {
2375 cmd.appendArg("force");
2376 }
2377 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002378 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002379 int code = e.getCode();
2380 if (code == VoldResponseCode.OpFailedStorageBusy) {
2381 rc = StorageResultCode.OperationFailedStorageBusy;
2382 } else {
2383 rc = StorageResultCode.OperationFailedInternalError;
2384 }
San Mehat02735bc2010-01-26 15:18:08 -08002385 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002386
2387 if (rc == StorageResultCode.OperationSucceeded) {
2388 synchronized (mAsecMountSet) {
2389 mAsecMountSet.remove(id);
2390 }
2391 }
San Mehat4270e1e2010-01-29 05:32:19 -08002392 return rc;
San Mehat9dba7092010-01-18 06:47:41 -08002393 }
2394
San Mehat6cdd9c02010-02-09 14:45:20 -08002395 public boolean isSecureContainerMounted(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002396 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat6cdd9c02010-02-09 14:45:20 -08002397 waitForReady();
2398 warnOnNotMounted();
2399
2400 synchronized (mAsecMountSet) {
2401 return mAsecMountSet.contains(id);
2402 }
2403 }
2404
San Mehat4270e1e2010-01-29 05:32:19 -08002405 public int renameSecureContainer(String oldId, String newId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002406 enforcePermission(android.Manifest.permission.ASEC_RENAME);
San Mehat207e5382010-02-04 20:46:54 -08002407 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002408 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002409
San Mehata181b212010-02-11 06:50:20 -08002410 synchronized (mAsecMountSet) {
San Mehat85451ee2010-02-24 08:54:18 -08002411 /*
Jason parks9ed98bc2011-01-17 09:58:35 -06002412 * Because a mounted container has active internal state which cannot be
San Mehat85451ee2010-02-24 08:54:18 -08002413 * changed while active, we must ensure both ids are not currently mounted.
2414 */
2415 if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
San Mehata181b212010-02-11 06:50:20 -08002416 return StorageResultCode.OperationFailedStorageMounted;
2417 }
2418 }
2419
San Mehatb1043402010-02-05 08:26:50 -08002420 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002421 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002422 mConnector.execute("asec", "rename", oldId, newId);
San Mehat4270e1e2010-01-29 05:32:19 -08002423 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002424 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002425 }
San Mehata181b212010-02-11 06:50:20 -08002426
San Mehat4270e1e2010-01-29 05:32:19 -08002427 return rc;
San Mehat45f61042010-01-23 08:12:43 -08002428 }
2429
San Mehat4270e1e2010-01-29 05:32:19 -08002430 public String getSecureContainerPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002431 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002432 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002433 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002434
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002435 final NativeDaemonEvent event;
San Mehat2d66cef2010-03-23 11:12:52 -07002436 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002437 event = mConnector.execute("asec", "path", id);
2438 event.checkCode(VoldResponseCode.AsecPathResult);
2439 return event.getMessage();
San Mehat2d66cef2010-03-23 11:12:52 -07002440 } catch (NativeDaemonConnectorException e) {
2441 int code = e.getCode();
2442 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Fredrik Helmera20c8ef2011-02-09 16:16:10 +01002443 Slog.i(TAG, String.format("Container '%s' not found", id));
2444 return null;
San Mehat22dd86e2010-01-12 12:21:18 -08002445 } else {
San Mehat2d66cef2010-03-23 11:12:52 -07002446 throw new IllegalStateException(String.format("Unexpected response code %d", code));
San Mehat22dd86e2010-01-12 12:21:18 -08002447 }
2448 }
San Mehat22dd86e2010-01-12 12:21:18 -08002449 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002450
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002451 public String getSecureContainerFilesystemPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002452 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002453 waitForReady();
2454 warnOnNotMounted();
2455
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002456 final NativeDaemonEvent event;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002457 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002458 event = mConnector.execute("asec", "fspath", id);
2459 event.checkCode(VoldResponseCode.AsecPathResult);
2460 return event.getMessage();
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002461 } catch (NativeDaemonConnectorException e) {
2462 int code = e.getCode();
2463 if (code == VoldResponseCode.OpFailedStorageNotFound) {
2464 Slog.i(TAG, String.format("Container '%s' not found", id));
2465 return null;
2466 } else {
2467 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2468 }
2469 }
2470 }
2471
Jeff Sharkey48877892015-03-18 11:27:19 -07002472 @Override
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002473 public void finishMediaUpdate() {
Jeff Sharkey9527b222015-06-24 15:24:48 -07002474 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
Rubin Xucd7a0142015-04-17 23:45:27 +01002475 throw new SecurityException("no permission to call finishMediaUpdate()");
2476 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002477 if (mUnmountSignal != null) {
2478 mUnmountSignal.countDown();
2479 } else {
2480 Slog.w(TAG, "Odd, nobody asked to unmount?");
2481 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002482 }
Kenny Root02c87302010-07-01 08:10:18 -07002483
Kenny Roota02b8b02010-08-05 16:14:17 -07002484 private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
2485 if (callerUid == android.os.Process.SYSTEM_UID) {
2486 return true;
2487 }
2488
Kenny Root02c87302010-07-01 08:10:18 -07002489 if (packageName == null) {
2490 return false;
2491 }
2492
Jeff Sharkeycd654482016-01-08 17:42:11 -07002493 final int packageUid = mPms.getPackageUid(packageName,
2494 PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callerUid));
Kenny Root02c87302010-07-01 08:10:18 -07002495
2496 if (DEBUG_OBB) {
2497 Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
2498 packageUid + ", callerUid = " + callerUid);
2499 }
2500
2501 return callerUid == packageUid;
2502 }
2503
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002504 public String getMountedObbPath(String rawPath) {
2505 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002506
Kenny Root02c87302010-07-01 08:10:18 -07002507 waitForReady();
2508 warnOnNotMounted();
2509
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002510 final ObbState state;
Rubin Xucd7a0142015-04-17 23:45:27 +01002511 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002512 state = mObbPathToStateMap.get(rawPath);
2513 }
2514 if (state == null) {
2515 Slog.w(TAG, "Failed to find OBB mounted at " + rawPath);
2516 return null;
2517 }
2518
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002519 final NativeDaemonEvent event;
Kenny Root02c87302010-07-01 08:10:18 -07002520 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07002521 event = mConnector.execute("obb", "path", state.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002522 event.checkCode(VoldResponseCode.AsecPathResult);
2523 return event.getMessage();
Kenny Root02c87302010-07-01 08:10:18 -07002524 } catch (NativeDaemonConnectorException e) {
2525 int code = e.getCode();
2526 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Kenny Roota02b8b02010-08-05 16:14:17 -07002527 return null;
Kenny Root02c87302010-07-01 08:10:18 -07002528 } else {
2529 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2530 }
2531 }
2532 }
2533
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002534 @Override
2535 public boolean isObbMounted(String rawPath) {
2536 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002537 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002538 return mObbPathToStateMap.containsKey(rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002539 }
Kenny Root02c87302010-07-01 08:10:18 -07002540 }
2541
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002542 @Override
2543 public void mountObb(
2544 String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) {
2545 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2546 Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
2547 Preconditions.checkNotNull(token, "token cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002548
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002549 final int callingUid = Binder.getCallingUid();
2550 final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce);
2551 final ObbAction action = new MountObbAction(obbState, key, callingUid);
Kenny Roota02b8b02010-08-05 16:14:17 -07002552 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
2553
2554 if (DEBUG_OBB)
2555 Slog.i(TAG, "Send to OBB handler: " + action.toString());
Kenny Root02c87302010-07-01 08:10:18 -07002556 }
2557
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002558 @Override
2559 public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
2560 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2561
2562 final ObbState existingState;
Rubin Xucd7a0142015-04-17 23:45:27 +01002563 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002564 existingState = mObbPathToStateMap.get(rawPath);
Kenny Rootf1121dc2010-09-29 07:30:53 -07002565 }
2566
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002567 if (existingState != null) {
2568 // TODO: separate state object from request data
2569 final int callingUid = Binder.getCallingUid();
2570 final ObbState newState = new ObbState(
2571 rawPath, existingState.canonicalPath, callingUid, token, nonce);
2572 final ObbAction action = new UnmountObbAction(newState, force);
2573 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root02c87302010-07-01 08:10:18 -07002574
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002575 if (DEBUG_OBB)
2576 Slog.i(TAG, "Send to OBB handler: " + action.toString());
2577 } else {
2578 Slog.w(TAG, "Unknown OBB mount at " + rawPath);
2579 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002580 }
2581
Ben Komalo444eca22011-09-01 15:17:44 -07002582 @Override
2583 public int getEncryptionState() {
2584 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2585 "no permission to access the crypt keeper");
2586
2587 waitForReady();
2588
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002589 final NativeDaemonEvent event;
Ben Komalo444eca22011-09-01 15:17:44 -07002590 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002591 event = mCryptConnector.execute("cryptfs", "cryptocomplete");
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002592 return Integer.parseInt(event.getMessage());
Ben Komalo444eca22011-09-01 15:17:44 -07002593 } catch (NumberFormatException e) {
2594 // Bad result - unexpected.
2595 Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
Sudheer Shankaf7341142016-10-18 17:15:18 -07002596 return StorageManager.ENCRYPTION_STATE_ERROR_UNKNOWN;
Ben Komalo444eca22011-09-01 15:17:44 -07002597 } catch (NativeDaemonConnectorException e) {
2598 // Something bad happened.
2599 Slog.w(TAG, "Error in communicating with cryptfs in validating");
Sudheer Shankaf7341142016-10-18 17:15:18 -07002600 return StorageManager.ENCRYPTION_STATE_ERROR_UNKNOWN;
Ben Komalo444eca22011-09-01 15:17:44 -07002601 }
2602 }
2603
2604 @Override
Jason parks5af0b912010-11-29 09:05:25 -06002605 public int decryptStorage(String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002606 if (TextUtils.isEmpty(password)) {
2607 throw new IllegalArgumentException("password cannot be empty");
Jason parks5af0b912010-11-29 09:05:25 -06002608 }
2609
Jason parks8888c592011-01-20 22:46:41 -06002610 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2611 "no permission to access the crypt keeper");
Jason parks5af0b912010-11-29 09:05:25 -06002612
2613 waitForReady();
2614
2615 if (DEBUG_EVENTS) {
2616 Slog.i(TAG, "decrypting storage...");
2617 }
2618
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002619 final NativeDaemonEvent event;
Jason parks5af0b912010-11-29 09:05:25 -06002620 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002621 event = mCryptConnector.execute("cryptfs", "checkpw", new SensitiveArg(password));
Jason parks9ed98bc2011-01-17 09:58:35 -06002622
Fredrik Roubertda6aedf2011-12-20 17:34:43 +01002623 final int code = Integer.parseInt(event.getMessage());
Jason parks9ed98bc2011-01-17 09:58:35 -06002624 if (code == 0) {
2625 // Decrypt was successful. Post a delayed message before restarting in order
2626 // to let the UI to clear itself
2627 mHandler.postDelayed(new Runnable() {
2628 public void run() {
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002629 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002630 mCryptConnector.execute("cryptfs", "restart");
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002631 } catch (NativeDaemonConnectorException e) {
2632 Slog.e(TAG, "problem executing in background", e);
2633 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002634 }
Jason parksf7b3cd42011-01-27 09:28:25 -06002635 }, 1000); // 1 second
Jason parks9ed98bc2011-01-17 09:58:35 -06002636 }
2637
2638 return code;
Jason parks5af0b912010-11-29 09:05:25 -06002639 } catch (NativeDaemonConnectorException e) {
2640 // Decryption failed
2641 return e.getCode();
2642 }
Jason parks5af0b912010-11-29 09:05:25 -06002643 }
2644
Paul Lawrence46791e72014-04-03 09:10:26 -07002645 public int encryptStorage(int type, String password) {
2646 if (TextUtils.isEmpty(password) && type != StorageManager.CRYPT_TYPE_DEFAULT) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002647 throw new IllegalArgumentException("password cannot be empty");
Jason parks56aa5322011-01-07 09:01:15 -06002648 }
2649
Jason parks8888c592011-01-20 22:46:41 -06002650 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2651 "no permission to access the crypt keeper");
Jason parks56aa5322011-01-07 09:01:15 -06002652
2653 waitForReady();
2654
2655 if (DEBUG_EVENTS) {
Jason parks8888c592011-01-20 22:46:41 -06002656 Slog.i(TAG, "encrypting storage...");
Jason parks56aa5322011-01-07 09:01:15 -06002657 }
2658
2659 try {
Paul Lawrence5096d9e2015-09-09 13:05:45 -07002660 if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
2661 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2662 CRYPTO_TYPES[type]);
2663 } else {
2664 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2665 CRYPTO_TYPES[type], new SensitiveArg(password));
2666 }
Jason parks56aa5322011-01-07 09:01:15 -06002667 } catch (NativeDaemonConnectorException e) {
2668 // Encryption failed
2669 return e.getCode();
2670 }
2671
2672 return 0;
2673 }
2674
Paul Lawrence8e397362014-01-27 15:22:30 -08002675 /** Set the password for encrypting the master key.
2676 * @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
2677 * @param password The password to set.
2678 */
2679 public int changeEncryptionPassword(int type, String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002680 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2681 "no permission to access the crypt keeper");
2682
2683 waitForReady();
2684
2685 if (DEBUG_EVENTS) {
2686 Slog.i(TAG, "changing encryption password...");
2687 }
2688
2689 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002690 NativeDaemonEvent event = mCryptConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type],
Paul Lawrence05487612015-06-09 13:35:38 -07002691 new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002692 return Integer.parseInt(event.getMessage());
Jason parksf7b3cd42011-01-27 09:28:25 -06002693 } catch (NativeDaemonConnectorException e) {
2694 // Encryption failed
2695 return e.getCode();
2696 }
2697 }
2698
Christopher Tate32418be2011-10-10 13:51:12 -07002699 /**
2700 * Validate a user-supplied password string with cryptfs
2701 */
2702 @Override
2703 public int verifyEncryptionPassword(String password) throws RemoteException {
2704 // Only the system process is permitted to validate passwords
2705 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2706 throw new SecurityException("no permission to access the crypt keeper");
2707 }
2708
2709 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2710 "no permission to access the crypt keeper");
2711
2712 if (TextUtils.isEmpty(password)) {
2713 throw new IllegalArgumentException("password cannot be empty");
2714 }
2715
2716 waitForReady();
2717
2718 if (DEBUG_EVENTS) {
2719 Slog.i(TAG, "validating encryption password...");
2720 }
2721
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002722 final NativeDaemonEvent event;
Christopher Tate32418be2011-10-10 13:51:12 -07002723 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002724 event = mCryptConnector.execute("cryptfs", "verifypw", new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002725 Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
2726 return Integer.parseInt(event.getMessage());
Christopher Tate32418be2011-10-10 13:51:12 -07002727 } catch (NativeDaemonConnectorException e) {
2728 // Encryption failed
2729 return e.getCode();
2730 }
2731 }
2732
Paul Lawrence8e397362014-01-27 15:22:30 -08002733 /**
2734 * Get the type of encryption used to encrypt the master key.
2735 * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
2736 */
2737 @Override
Svetoslav16e4a1a2014-09-29 18:16:20 -07002738 public int getPasswordType() {
Paul Lawrence76a40572017-03-15 11:08:04 -07002739 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Paul Lawrence9de713d2016-05-02 22:45:33 +00002740 "no permission to access the crypt keeper");
2741
Paul Lawrence8e397362014-01-27 15:22:30 -08002742 waitForReady();
2743
2744 final NativeDaemonEvent event;
2745 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002746 event = mCryptConnector.execute("cryptfs", "getpwtype");
Paul Lawrence8e397362014-01-27 15:22:30 -08002747 for (int i = 0; i < CRYPTO_TYPES.length; ++i) {
2748 if (CRYPTO_TYPES[i].equals(event.getMessage()))
2749 return i;
2750 }
2751
2752 throw new IllegalStateException("unexpected return from cryptfs");
2753 } catch (NativeDaemonConnectorException e) {
2754 throw e.rethrowAsParcelableException();
2755 }
2756 }
2757
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002758 /**
2759 * Set a field in the crypto header.
2760 * @param field field to set
2761 * @param contents contents to set in field
2762 */
2763 @Override
2764 public void setField(String field, String contents) throws RemoteException {
Paul Lawrence76a40572017-03-15 11:08:04 -07002765 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002766 "no permission to access the crypt keeper");
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002767
2768 waitForReady();
2769
2770 final NativeDaemonEvent event;
2771 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002772 event = mCryptConnector.execute("cryptfs", "setfield", field, contents);
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002773 } catch (NativeDaemonConnectorException e) {
2774 throw e.rethrowAsParcelableException();
2775 }
2776 }
2777
2778 /**
2779 * Gets a field from the crypto header.
2780 * @param field field to get
2781 * @return contents of field
2782 */
2783 @Override
2784 public String getField(String field) throws RemoteException {
Paul Lawrence76a40572017-03-15 11:08:04 -07002785 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002786 "no permission to access the crypt keeper");
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002787
2788 waitForReady();
2789
2790 final NativeDaemonEvent event;
2791 try {
2792 final String[] contents = NativeDaemonEvent.filterMessageList(
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002793 mCryptConnector.executeForList("cryptfs", "getfield", field),
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002794 VoldResponseCode.CryptfsGetfieldResult);
2795 String result = new String();
2796 for (String content : contents) {
2797 result += content;
2798 }
2799 return result;
2800 } catch (NativeDaemonConnectorException e) {
2801 throw e.rethrowAsParcelableException();
2802 }
2803 }
2804
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002805 /**
2806 * Is userdata convertible to file based encryption?
2807 * @return non zero for convertible
2808 */
2809 @Override
2810 public boolean isConvertibleToFBE() throws RemoteException {
Paul Lawrence76a40572017-03-15 11:08:04 -07002811 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002812 "no permission to access the crypt keeper");
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002813
2814 waitForReady();
2815
2816 final NativeDaemonEvent event;
2817 try {
2818 event = mCryptConnector.execute("cryptfs", "isConvertibleToFBE");
2819 return Integer.parseInt(event.getMessage()) != 0;
2820 } catch (NativeDaemonConnectorException e) {
2821 throw e.rethrowAsParcelableException();
2822 }
2823 }
2824
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002825 @Override
Paul Lawrence945490c2014-03-27 16:37:28 +00002826 public String getPassword() throws RemoteException {
Paul Lawrence76a40572017-03-15 11:08:04 -07002827 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Rubin Xucd7a0142015-04-17 23:45:27 +01002828 "only keyguard can retrieve password");
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002829
Paul Lawrence945490c2014-03-27 16:37:28 +00002830 if (!isReady()) {
2831 return new String();
2832 }
2833
2834 final NativeDaemonEvent event;
2835 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002836 event = mCryptConnector.execute("cryptfs", "getpw");
Paul Lawrence24063b52015-01-06 13:11:23 -08002837 if ("-1".equals(event.getMessage())) {
2838 // -1 equals no password
2839 return null;
2840 }
Paul Lawrence05487612015-06-09 13:35:38 -07002841 return event.getMessage();
Paul Lawrence945490c2014-03-27 16:37:28 +00002842 } catch (NativeDaemonConnectorException e) {
2843 throw e.rethrowAsParcelableException();
Paul Lawrence24063b52015-01-06 13:11:23 -08002844 } catch (IllegalArgumentException e) {
2845 Slog.e(TAG, "Invalid response to getPassword");
2846 return null;
Paul Lawrence945490c2014-03-27 16:37:28 +00002847 }
2848 }
2849
2850 @Override
2851 public void clearPassword() throws RemoteException {
Paul Lawrence76a40572017-03-15 11:08:04 -07002852 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002853 "only keyguard can clear password");
2854
Paul Lawrence945490c2014-03-27 16:37:28 +00002855 if (!isReady()) {
2856 return;
2857 }
2858
2859 final NativeDaemonEvent event;
2860 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002861 event = mCryptConnector.execute("cryptfs", "clearpw");
Paul Lawrence945490c2014-03-27 16:37:28 +00002862 } catch (NativeDaemonConnectorException e) {
2863 throw e.rethrowAsParcelableException();
2864 }
2865 }
2866
2867 @Override
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002868 public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002869 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002870 waitForReady();
2871
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002872 try {
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002873 mCryptConnector.execute("cryptfs", "create_user_key", userId, serialNumber,
2874 ephemeral ? 1 : 0);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002875 } catch (NativeDaemonConnectorException e) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002876 throw e.rethrowAsParcelableException();
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002877 }
2878 }
2879
Paul Crowley7ec733f2015-05-19 12:42:00 +01002880 @Override
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002881 public void destroyUserKey(int userId) {
2882 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowley7ec733f2015-05-19 12:42:00 +01002883 waitForReady();
2884
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002885 try {
2886 mCryptConnector.execute("cryptfs", "destroy_user_key", userId);
2887 } catch (NativeDaemonConnectorException e) {
2888 throw e.rethrowAsParcelableException();
2889 }
2890 }
2891
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002892 private SensitiveArg encodeBytes(byte[] bytes) {
2893 if (ArrayUtils.isEmpty(bytes)) {
2894 return new SensitiveArg("!");
2895 } else {
2896 return new SensitiveArg(HexDump.toHexString(bytes));
2897 }
2898 }
2899
Paul Crowleycc701552016-05-17 14:18:49 -07002900 /*
2901 * Add this token/secret pair to the set of ways we can recover a disk encryption key.
2902 * Changing the token/secret for a disk encryption key is done in two phases: first, adding
2903 * a new token/secret pair with this call, then delting all other pairs with
2904 * fixateNewestUserKeyAuth. This allows other places where a credential is used, such as
2905 * Gatekeeper, to be updated between the two calls.
2906 */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002907 @Override
Paul Crowleycc701552016-05-17 14:18:49 -07002908 public void addUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002909 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2910 waitForReady();
2911
2912 try {
Paul Crowleycc701552016-05-17 14:18:49 -07002913 mCryptConnector.execute("cryptfs", "add_user_key_auth", userId, serialNumber,
2914 encodeBytes(token), encodeBytes(secret));
2915 } catch (NativeDaemonConnectorException e) {
2916 throw e.rethrowAsParcelableException();
2917 }
2918 }
2919
2920 /*
2921 * Delete all disk encryption token/secret pairs except the most recently added one
2922 */
2923 @Override
2924 public void fixateNewestUserKeyAuth(int userId) {
2925 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2926 waitForReady();
2927
2928 try {
2929 mCryptConnector.execute("cryptfs", "fixate_newest_user_key_auth", userId);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002930 } catch (NativeDaemonConnectorException e) {
2931 throw e.rethrowAsParcelableException();
2932 }
2933 }
2934
2935 @Override
2936 public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002937 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2938 waitForReady();
2939
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002940 if (StorageManager.isFileEncryptedNativeOrEmulated()) {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002941 // When a user has secure lock screen, require secret to actually unlock.
2942 // This check is mostly in place for emulation mode.
2943 if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(secret)) {
2944 throw new IllegalStateException("Secret required to unlock secure user " + userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002945 }
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07002946
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002947 try {
2948 mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber,
2949 encodeBytes(token), encodeBytes(secret));
2950 } catch (NativeDaemonConnectorException e) {
2951 throw e.rethrowAsParcelableException();
2952 }
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002953 }
2954
2955 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002956 mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002957 }
Paul Crowley9139a782017-07-26 13:29:25 -07002958 if (userId == UserHandle.USER_SYSTEM) {
2959 String propertyName = "sys.user." + userId + ".ce_available";
2960 Slog.d(TAG, "Setting property: " + propertyName + "=true");
2961 SystemProperties.set(propertyName, "true");
2962 }
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002963 }
2964
2965 @Override
2966 public void lockUserKey(int userId) {
2967 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2968 waitForReady();
2969
2970 try {
2971 mCryptConnector.execute("cryptfs", "lock_user_key", userId);
2972 } catch (NativeDaemonConnectorException e) {
2973 throw e.rethrowAsParcelableException();
2974 }
2975
2976 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002977 mLocalUnlockedUsers = ArrayUtils.removeInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002978 }
2979 }
2980
2981 @Override
2982 public boolean isUserKeyUnlocked(int userId) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002983 synchronized (mLock) {
2984 return ArrayUtils.contains(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002985 }
2986 }
2987
2988 @Override
Jeff Sharkey47f71082016-02-01 17:03:54 -07002989 public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002990 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2991 waitForReady();
2992
2993 try {
2994 mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid),
Jeff Sharkey47f71082016-02-01 17:03:54 -07002995 userId, serialNumber, flags);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002996 } catch (NativeDaemonConnectorException e) {
2997 throw e.rethrowAsParcelableException();
Paul Crowley7ec733f2015-05-19 12:42:00 +01002998 }
2999 }
3000
Paul Crowleybcf48ed2015-04-22 13:36:59 +01003001 @Override
Jeff Sharkeyfcf1e552016-04-14 20:44:58 -06003002 public void destroyUserStorage(String volumeUuid, int userId, int flags) {
3003 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
3004 waitForReady();
3005
3006 try {
3007 mCryptConnector.execute("cryptfs", "destroy_user_storage", escapeNull(volumeUuid),
3008 userId, flags);
3009 } catch (NativeDaemonConnectorException e) {
3010 throw e.rethrowAsParcelableException();
3011 }
3012 }
3013
Rubin Xuee67b612017-04-27 17:01:05 +01003014 @Override
3015 public void secdiscard(String path) {
3016 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
3017 waitForReady();
3018
3019 try {
3020 mCryptConnector.execute("cryptfs", "secdiscard", escapeNull(path));
3021 } catch (NativeDaemonConnectorException e) {
3022 throw e.rethrowAsParcelableException();
3023 }
3024 }
3025
Daichi Hironoe56740d2017-02-02 13:56:45 +09003026 class AppFuseMountScope extends AppFuseBridge.MountScope {
Daichi Hirono812c95d2017-02-08 16:20:20 +09003027 boolean opened = false;
3028
3029 public AppFuseMountScope(int uid, int pid, int mountId) {
3030 super(uid, pid, mountId);
3031 }
3032
3033 @Override
3034 public ParcelFileDescriptor open() throws NativeDaemonConnectorException {
3035 final NativeDaemonEvent event = StorageManagerService.this.mConnector.execute(
3036 "appfuse", "mount", uid, Process.myPid(), mountId);
3037 opened = true;
3038 if (event.getFileDescriptors() == null ||
3039 event.getFileDescriptors().length == 0) {
3040 throw new NativeDaemonConnectorException("Cannot obtain device FD");
3041 }
3042 return new ParcelFileDescriptor(event.getFileDescriptors()[0]);
Daichi Hirono9fb00182016-11-08 14:12:17 +09003043 }
3044
3045 @Override
Daichi Hironoe56740d2017-02-02 13:56:45 +09003046 public void close() throws Exception {
Daichi Hirono812c95d2017-02-08 16:20:20 +09003047 if (opened) {
3048 mConnector.execute("appfuse", "unmount", uid, Process.myPid(), mountId);
3049 opened = false;
3050 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09003051 }
3052 }
3053
3054 @Override
Daichi Hirono812c95d2017-02-08 16:20:20 +09003055 public @Nullable AppFuseMount mountProxyFileDescriptorBridge() {
Daichi Hironoe56740d2017-02-02 13:56:45 +09003056 Slog.v(TAG, "mountProxyFileDescriptorBridge");
Daichi Hirono9fb00182016-11-08 14:12:17 +09003057 final int uid = Binder.getCallingUid();
3058 final int pid = Binder.getCallingPid();
Daichi Hirono9fb00182016-11-08 14:12:17 +09003059
Daichi Hironoe56740d2017-02-02 13:56:45 +09003060 while (true) {
3061 synchronized (mAppFuseLock) {
3062 boolean newlyCreated = false;
3063 if (mAppFuseBridge == null) {
3064 mAppFuseBridge = new AppFuseBridge();
3065 new Thread(mAppFuseBridge, AppFuseBridge.TAG).start();
3066 newlyCreated = true;
Daichi Hirono9fb00182016-11-08 14:12:17 +09003067 }
Daichi Hironoe56740d2017-02-02 13:56:45 +09003068 try {
3069 final int name = mNextAppFuseName++;
3070 try {
3071 return new AppFuseMount(
Daichi Hirono812c95d2017-02-08 16:20:20 +09003072 name, mAppFuseBridge.addBridge(new AppFuseMountScope(uid, pid, name)));
3073 } catch (FuseUnavailableMountException e) {
Daichi Hironoe56740d2017-02-02 13:56:45 +09003074 if (newlyCreated) {
3075 // If newly created bridge fails, it's a real error.
Daichi Hirono812c95d2017-02-08 16:20:20 +09003076 Slog.e(TAG, "", e);
3077 return null;
Daichi Hironoe56740d2017-02-02 13:56:45 +09003078 }
3079 // It seems the thread of mAppFuseBridge has already been terminated.
3080 mAppFuseBridge = null;
3081 }
3082 } catch (NativeDaemonConnectorException e) {
3083 throw e.rethrowAsParcelableException();
3084 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09003085 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09003086 }
3087 }
3088
3089 @Override
Daichi Hirono812c95d2017-02-08 16:20:20 +09003090 public @Nullable ParcelFileDescriptor openProxyFileDescriptor(
3091 int mountId, int fileId, int mode) {
3092 Slog.v(TAG, "mountProxyFileDescriptor");
Daichi Hirono9fb00182016-11-08 14:12:17 +09003093 final int pid = Binder.getCallingPid();
3094 try {
3095 synchronized (mAppFuseLock) {
Daichi Hironoe56740d2017-02-02 13:56:45 +09003096 if (mAppFuseBridge == null) {
Daichi Hirono812c95d2017-02-08 16:20:20 +09003097 Slog.e(TAG, "FuseBridge has not been created");
3098 return null;
Daichi Hirono9fb00182016-11-08 14:12:17 +09003099 }
Daichi Hironoe56740d2017-02-02 13:56:45 +09003100 return mAppFuseBridge.openFile(pid, mountId, fileId, mode);
Daichi Hirono9fb00182016-11-08 14:12:17 +09003101 }
Daichi Hirono812c95d2017-02-08 16:20:20 +09003102 } catch (FuseUnavailableMountException | InterruptedException error) {
3103 Slog.v(TAG, "The mount point has already been invalid", error);
3104 return null;
Daichi Hirono9fb00182016-11-08 14:12:17 +09003105 }
3106 }
3107
Daichi Hirono9e8d9e22015-11-13 14:37:00 +09003108 @Override
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003109 public int mkdirs(String callingPkg, String appPath) {
3110 final int userId = UserHandle.getUserId(Binder.getCallingUid());
3111 final UserEnvironment userEnv = new UserEnvironment(userId);
3112
3113 // Validate that reported package name belongs to caller
3114 final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
3115 Context.APP_OPS_SERVICE);
3116 appOps.checkPackage(Binder.getCallingUid(), callingPkg);
3117
Jeff Sharkey48877892015-03-18 11:27:19 -07003118 File appFile = null;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003119 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07003120 appFile = new File(appPath).getCanonicalFile();
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003121 } catch (IOException e) {
3122 Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
3123 return -1;
3124 }
3125
3126 // Try translating the app path into a vold path, but require that it
3127 // belong to the calling package.
Jeff Sharkey48877892015-03-18 11:27:19 -07003128 if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) ||
3129 FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) ||
3130 FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) {
3131 appPath = appFile.getAbsolutePath();
3132 if (!appPath.endsWith("/")) {
3133 appPath = appPath + "/";
3134 }
3135
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003136 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07003137 mConnector.execute("volume", "mkdirs", appPath);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003138 return 0;
3139 } catch (NativeDaemonConnectorException e) {
3140 return e.getCode();
3141 }
3142 }
3143
Jeff Sharkey48877892015-03-18 11:27:19 -07003144 throw new SecurityException("Invalid mkdirs path: " + appFile);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003145 }
3146
3147 @Override
Jeff Sharkey46349872015-07-28 10:49:47 -07003148 public StorageVolume[] getVolumeList(int uid, String packageName, int flags) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003149 final int userId = UserHandle.getUserId(uid);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003150
Jeff Sharkey46349872015-07-28 10:49:47 -07003151 final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0;
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003152 final boolean realState = (flags & StorageManager.FLAG_REAL_STATE) != 0;
3153 final boolean includeInvisible = (flags & StorageManager.FLAG_INCLUDE_INVISIBLE) != 0;
Jeff Sharkey46349872015-07-28 10:49:47 -07003154
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003155 final boolean userKeyUnlocked;
3156 final boolean storagePermission;
3157 final long token = Binder.clearCallingIdentity();
Svetoslav38c3dbb2015-07-14 11:27:06 -07003158 try {
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003159 userKeyUnlocked = isUserKeyUnlocked(userId);
Sudheer Shanka2250d562016-11-07 15:41:02 -08003160 storagePermission = mStorageManagerInternal.hasExternalStorage(uid, packageName);
Svetoslav38c3dbb2015-07-14 11:27:06 -07003161 } finally {
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003162 Binder.restoreCallingIdentity(token);
Svetoslav38c3dbb2015-07-14 11:27:06 -07003163 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003164
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003165 boolean foundPrimary = false;
3166
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003167 final ArrayList<StorageVolume> res = new ArrayList<>();
Jeff Sharkey48877892015-03-18 11:27:19 -07003168 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003169 for (int i = 0; i < mVolumes.size(); i++) {
3170 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003171 switch (vol.getType()) {
3172 case VolumeInfo.TYPE_PUBLIC:
3173 case VolumeInfo.TYPE_EMULATED:
3174 break;
3175 default:
3176 continue;
3177 }
3178
3179 boolean match = false;
3180 if (forWrite) {
3181 match = vol.isVisibleForWrite(userId);
3182 } else {
Felipe Leme123a0e72016-06-10 11:09:11 -07003183 match = vol.isVisibleForRead(userId)
3184 || (includeInvisible && vol.getPath() != null);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003185 }
3186 if (!match) continue;
3187
3188 boolean reportUnmounted = false;
3189 if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !userKeyUnlocked) {
3190 reportUnmounted = true;
3191 } else if (!storagePermission && !realState) {
3192 reportUnmounted = true;
3193 }
3194
3195 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
3196 reportUnmounted);
3197 if (vol.isPrimary()) {
3198 res.add(0, userVol);
3199 foundPrimary = true;
3200 } else {
3201 res.add(userVol);
Jeff Sharkeyb049e212012-09-07 23:16:01 -07003202 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003203 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003204 }
Jeff Sharkey48877892015-03-18 11:27:19 -07003205
3206 if (!foundPrimary) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003207 Log.w(TAG, "No primary storage defined yet; hacking together a stub");
Jeff Sharkey48877892015-03-18 11:27:19 -07003208
3209 final boolean primaryPhysical = SystemProperties.getBoolean(
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003210 StorageManager.PROP_PRIMARY_PHYSICAL, false);
Jeff Sharkey48877892015-03-18 11:27:19 -07003211
3212 final String id = "stub_primary";
3213 final File path = Environment.getLegacyExternalStorageDirectory();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003214 final String description = mContext.getString(android.R.string.unknownName);
Jeff Sharkey48877892015-03-18 11:27:19 -07003215 final boolean primary = true;
3216 final boolean removable = primaryPhysical;
3217 final boolean emulated = !primaryPhysical;
3218 final long mtpReserveSize = 0L;
3219 final boolean allowMassStorage = false;
3220 final long maxFileSize = 0L;
3221 final UserHandle owner = new UserHandle(userId);
3222 final String uuid = null;
Jeff Sharkey48877892015-03-18 11:27:19 -07003223 final String state = Environment.MEDIA_REMOVED;
3224
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07003225 res.add(0, new StorageVolume(id, StorageVolume.STORAGE_ID_INVALID, path,
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003226 description, primary, removable, emulated, mtpReserveSize,
3227 allowMassStorage, maxFileSize, owner, uuid, state));
Jeff Sharkey48877892015-03-18 11:27:19 -07003228 }
3229
3230 return res.toArray(new StorageVolume[res.size()]);
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003231 }
3232
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003233 @Override
3234 public DiskInfo[] getDisks() {
3235 synchronized (mLock) {
3236 final DiskInfo[] res = new DiskInfo[mDisks.size()];
3237 for (int i = 0; i < mDisks.size(); i++) {
3238 res[i] = mDisks.valueAt(i);
3239 }
3240 return res;
3241 }
3242 }
3243
3244 @Override
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003245 public VolumeInfo[] getVolumes(int flags) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003246 synchronized (mLock) {
3247 final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
3248 for (int i = 0; i < mVolumes.size(); i++) {
3249 res[i] = mVolumes.valueAt(i);
3250 }
3251 return res;
3252 }
3253 }
3254
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003255 @Override
3256 public VolumeRecord[] getVolumeRecords(int flags) {
3257 synchronized (mLock) {
3258 final VolumeRecord[] res = new VolumeRecord[mRecords.size()];
3259 for (int i = 0; i < mRecords.size(); i++) {
3260 res[i] = mRecords.valueAt(i);
3261 }
3262 return res;
3263 }
3264 }
3265
Jeff Sharkey9bed0702017-01-23 20:37:05 -07003266 @Override
3267 public long getCacheQuotaBytes(String volumeUuid, int uid) {
3268 if (uid != Binder.getCallingUid()) {
3269 mContext.enforceCallingPermission(android.Manifest.permission.STORAGE_INTERNAL, TAG);
3270 }
Daniel Nishi80fdb012017-03-09 14:30:07 -08003271 final long token = Binder.clearCallingIdentity();
3272 final StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class);
3273 try {
3274 return stats.getCacheQuotaBytes(volumeUuid, uid);
3275 } finally {
3276 Binder.restoreCallingIdentity(token);
3277 }
Jeff Sharkey9bed0702017-01-23 20:37:05 -07003278 }
3279
3280 @Override
3281 public long getCacheSizeBytes(String volumeUuid, int uid) {
3282 if (uid != Binder.getCallingUid()) {
3283 mContext.enforceCallingPermission(android.Manifest.permission.STORAGE_INTERNAL, TAG);
3284 }
3285 final long token = Binder.clearCallingIdentity();
3286 try {
3287 return mContext.getSystemService(StorageStatsManager.class)
3288 .queryStatsForUid(volumeUuid, uid).getCacheBytes();
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06003289 } catch (IOException e) {
3290 throw new ParcelableException(e);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07003291 } finally {
3292 Binder.restoreCallingIdentity(token);
3293 }
3294 }
3295
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003296 private int adjustAllocateFlags(int flags, int callingUid, String callingPackage) {
3297 // Require permission to allocate aggressively
3298 if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003299 mContext.enforceCallingOrSelfPermission(
3300 android.Manifest.permission.ALLOCATE_AGGRESSIVE, TAG);
3301 }
3302
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003303 // Apps normally can't directly defy reserved space
3304 flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED;
3305 flags &= ~StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED;
3306
3307 // However, if app is actively using the camera, then we're willing to
3308 // clear up to half of the reserved cache space, since the user might be
3309 // trying to capture an important memory.
3310 final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
3311 final long token = Binder.clearCallingIdentity();
3312 try {
3313 if (appOps.isOperationActive(AppOpsManager.OP_CAMERA, callingUid, callingPackage)) {
3314 Slog.d(TAG, "UID " + callingUid + " is actively using camera;"
3315 + " letting them defy reserved cached data");
3316 flags |= StorageManager.FLAG_ALLOCATE_DEFY_HALF_RESERVED;
3317 }
3318 } finally {
3319 Binder.restoreCallingIdentity(token);
3320 }
3321
3322 return flags;
3323 }
3324
3325 @Override
3326 public long getAllocatableBytes(String volumeUuid, int flags, String callingPackage) {
3327 flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage);
3328
3329 final StorageManager storage = mContext.getSystemService(StorageManager.class);
3330 final StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003331 final long token = Binder.clearCallingIdentity();
3332 try {
3333 // In general, apps can allocate as much space as they want, except
3334 // we never let them eat into either the minimum cache space or into
Jeff Sharkeyddff8072017-05-26 13:10:46 -06003335 // the low disk warning space. To avoid user confusion, this logic
3336 // should be kept in sync with getFreeBytes().
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003337 final File path = storage.findPathForUuid(volumeUuid);
Jeff Sharkeyddff8072017-05-26 13:10:46 -06003338
3339 final long usable = path.getUsableSpace();
3340 final long lowReserved = storage.getStorageLowBytes(path);
3341 final long fullReserved = storage.getStorageFullBytes(path);
3342
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003343 if (stats.isQuotaSupported(volumeUuid)) {
Jeff Sharkeyddff8072017-05-26 13:10:46 -06003344 final long cacheTotal = stats.getCacheBytes(volumeUuid);
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003345 final long cacheReserved = storage.getStorageCacheBytes(path, flags);
Jeff Sharkeyddff8072017-05-26 13:10:46 -06003346 final long cacheClearable = Math.max(0, cacheTotal - cacheReserved);
3347
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003348 if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
3349 return Math.max(0, (usable + cacheClearable) - fullReserved);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003350 } else {
Jeff Sharkeyddff8072017-05-26 13:10:46 -06003351 return Math.max(0, (usable + cacheClearable) - lowReserved);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003352 }
3353 } else {
3354 // When we don't have fast quota information, we ignore cached
3355 // data and only consider unused bytes.
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003356 if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
Jeff Sharkeyddff8072017-05-26 13:10:46 -06003357 return Math.max(0, usable - fullReserved);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003358 } else {
Jeff Sharkeyddff8072017-05-26 13:10:46 -06003359 return Math.max(0, usable - lowReserved);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003360 }
3361 }
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06003362 } catch (IOException e) {
3363 throw new ParcelableException(e);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003364 } finally {
3365 Binder.restoreCallingIdentity(token);
3366 }
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07003367 }
3368
3369 @Override
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003370 public void allocateBytes(String volumeUuid, long bytes, int flags, String callingPackage) {
3371 flags = adjustAllocateFlags(flags, Binder.getCallingUid(), callingPackage);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003372
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003373 final long allocatableBytes = getAllocatableBytes(volumeUuid, flags, callingPackage);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003374 if (bytes > allocatableBytes) {
3375 throw new ParcelableException(new IOException("Failed to allocate " + bytes
3376 + " because only " + allocatableBytes + " allocatable"));
3377 }
3378
Jeff Sharkey35e46d22017-06-09 10:01:20 -06003379 final StorageManager storage = mContext.getSystemService(StorageManager.class);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003380 final long token = Binder.clearCallingIdentity();
3381 try {
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06003382 // Free up enough disk space to satisfy both the requested allocation
3383 // and our low disk warning space.
3384 final File path = storage.findPathForUuid(volumeUuid);
Jeff Sharkeyddff8072017-05-26 13:10:46 -06003385 if ((flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0) {
3386 bytes += storage.getStorageFullBytes(path);
3387 } else {
3388 bytes += storage.getStorageLowBytes(path);
3389 }
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06003390
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003391 mPms.freeStorage(volumeUuid, bytes, flags);
3392 } catch (IOException e) {
3393 throw new ParcelableException(e);
3394 } finally {
3395 Binder.restoreCallingIdentity(token);
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07003396 }
3397 }
3398
Kenny Rootaf9d6672010-10-08 09:21:39 -07003399 private void addObbStateLocked(ObbState obbState) throws RemoteException {
3400 final IBinder binder = obbState.getBinder();
3401 List<ObbState> obbStates = mObbMounts.get(binder);
Kenny Root5919ac62010-10-05 09:49:40 -07003402
Kenny Rootaf9d6672010-10-08 09:21:39 -07003403 if (obbStates == null) {
3404 obbStates = new ArrayList<ObbState>();
3405 mObbMounts.put(binder, obbStates);
3406 } else {
3407 for (final ObbState o : obbStates) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003408 if (o.rawPath.equals(obbState.rawPath)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003409 throw new IllegalStateException("Attempt to add ObbState twice. "
Sudheer Shanka2250d562016-11-07 15:41:02 -08003410 + "This indicates an error in the StorageManagerService logic.");
Kenny Root5919ac62010-10-05 09:49:40 -07003411 }
3412 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003413 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003414
3415 obbStates.add(obbState);
3416 try {
3417 obbState.link();
3418 } catch (RemoteException e) {
3419 /*
3420 * The binder died before we could link it, so clean up our state
3421 * and return failure.
3422 */
3423 obbStates.remove(obbState);
3424 if (obbStates.isEmpty()) {
3425 mObbMounts.remove(binder);
3426 }
3427
3428 // Rethrow the error so mountObb can get it
3429 throw e;
3430 }
3431
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003432 mObbPathToStateMap.put(obbState.rawPath, obbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003433 }
3434
Kenny Rootaf9d6672010-10-08 09:21:39 -07003435 private void removeObbStateLocked(ObbState obbState) {
3436 final IBinder binder = obbState.getBinder();
3437 final List<ObbState> obbStates = mObbMounts.get(binder);
3438 if (obbStates != null) {
3439 if (obbStates.remove(obbState)) {
3440 obbState.unlink();
Kenny Root05105f72010-09-22 17:29:43 -07003441 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003442 if (obbStates.isEmpty()) {
3443 mObbMounts.remove(binder);
3444 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003445 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003446
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003447 mObbPathToStateMap.remove(obbState.rawPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003448 }
3449
Kenny Roota02b8b02010-08-05 16:14:17 -07003450 private class ObbActionHandler extends Handler {
3451 private boolean mBound = false;
Kenny Root480afe72010-10-07 10:17:50 -07003452 private final List<ObbAction> mActions = new LinkedList<ObbAction>();
Kenny Roota02b8b02010-08-05 16:14:17 -07003453
3454 ObbActionHandler(Looper l) {
3455 super(l);
3456 }
3457
3458 @Override
3459 public void handleMessage(Message msg) {
3460 switch (msg.what) {
3461 case OBB_RUN_ACTION: {
Kenny Root480afe72010-10-07 10:17:50 -07003462 final ObbAction action = (ObbAction) msg.obj;
Kenny Roota02b8b02010-08-05 16:14:17 -07003463
3464 if (DEBUG_OBB)
3465 Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
3466
3467 // If a bind was already initiated we don't really
3468 // need to do anything. The pending install
3469 // will be processed later on.
3470 if (!mBound) {
3471 // If this is the only one pending we might
3472 // have to bind to the service again.
3473 if (!connectToService()) {
3474 Slog.e(TAG, "Failed to bind to media container service");
3475 action.handleError();
3476 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003477 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003478 }
Kenny Root735de3b2010-09-30 14:11:39 -07003479
Kenny Root735de3b2010-09-30 14:11:39 -07003480 mActions.add(action);
Kenny Roota02b8b02010-08-05 16:14:17 -07003481 break;
3482 }
3483 case OBB_MCS_BOUND: {
3484 if (DEBUG_OBB)
3485 Slog.i(TAG, "OBB_MCS_BOUND");
3486 if (msg.obj != null) {
3487 mContainerService = (IMediaContainerService) msg.obj;
3488 }
3489 if (mContainerService == null) {
3490 // Something seriously wrong. Bail out
3491 Slog.e(TAG, "Cannot bind to media container service");
3492 for (ObbAction action : mActions) {
3493 // Indicate service bind error
3494 action.handleError();
3495 }
3496 mActions.clear();
3497 } else if (mActions.size() > 0) {
Kenny Root480afe72010-10-07 10:17:50 -07003498 final ObbAction action = mActions.get(0);
Kenny Roota02b8b02010-08-05 16:14:17 -07003499 if (action != null) {
3500 action.execute(this);
3501 }
3502 } else {
3503 // Should never happen ideally.
3504 Slog.w(TAG, "Empty queue");
3505 }
3506 break;
3507 }
3508 case OBB_MCS_RECONNECT: {
3509 if (DEBUG_OBB)
3510 Slog.i(TAG, "OBB_MCS_RECONNECT");
3511 if (mActions.size() > 0) {
3512 if (mBound) {
3513 disconnectService();
3514 }
3515 if (!connectToService()) {
3516 Slog.e(TAG, "Failed to bind to media container service");
3517 for (ObbAction action : mActions) {
3518 // Indicate service bind error
3519 action.handleError();
3520 }
3521 mActions.clear();
3522 }
3523 }
3524 break;
3525 }
3526 case OBB_MCS_UNBIND: {
3527 if (DEBUG_OBB)
3528 Slog.i(TAG, "OBB_MCS_UNBIND");
3529
3530 // Delete pending install
3531 if (mActions.size() > 0) {
3532 mActions.remove(0);
3533 }
3534 if (mActions.size() == 0) {
3535 if (mBound) {
3536 disconnectService();
3537 }
3538 } else {
3539 // There are more pending requests in queue.
3540 // Just post MCS_BOUND message to trigger processing
3541 // of next pending install.
3542 mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
3543 }
3544 break;
3545 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003546 case OBB_FLUSH_MOUNT_STATE: {
3547 final String path = (String) msg.obj;
3548
3549 if (DEBUG_OBB)
3550 Slog.i(TAG, "Flushing all OBB state for path " + path);
3551
3552 synchronized (mObbMounts) {
3553 final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
3554
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003555 final Iterator<ObbState> i = mObbPathToStateMap.values().iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003556 while (i.hasNext()) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003557 final ObbState state = i.next();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003558
3559 /*
3560 * If this entry's source file is in the volume path
3561 * that got unmounted, remove it because it's no
3562 * longer valid.
3563 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003564 if (state.canonicalPath.startsWith(path)) {
3565 obbStatesToRemove.add(state);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003566 }
3567 }
3568
3569 for (final ObbState obbState : obbStatesToRemove) {
3570 if (DEBUG_OBB)
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003571 Slog.i(TAG, "Removing state for " + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003572
3573 removeObbStateLocked(obbState);
3574
3575 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003576 obbState.token.onObbResult(obbState.rawPath, obbState.nonce,
Kenny Rootaf9d6672010-10-08 09:21:39 -07003577 OnObbStateChangeListener.UNMOUNTED);
3578 } catch (RemoteException e) {
3579 Slog.i(TAG, "Couldn't send unmount notification for OBB: "
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003580 + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003581 }
3582 }
3583 }
3584 break;
3585 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003586 }
3587 }
3588
3589 private boolean connectToService() {
3590 if (DEBUG_OBB)
3591 Slog.i(TAG, "Trying to bind to DefaultContainerService");
3592
3593 Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Jeff Sharkey6dce4962015-07-03 18:08:41 -07003594 if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE,
Xiaohui Chene4de5a02015-09-22 15:33:31 -07003595 UserHandle.SYSTEM)) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003596 mBound = true;
3597 return true;
3598 }
3599 return false;
3600 }
3601
3602 private void disconnectService() {
3603 mContainerService = null;
3604 mBound = false;
3605 mContext.unbindService(mDefContainerConn);
3606 }
3607 }
3608
3609 abstract class ObbAction {
3610 private static final int MAX_RETRIES = 3;
3611 private int mRetries;
3612
3613 ObbState mObbState;
3614
3615 ObbAction(ObbState obbState) {
3616 mObbState = obbState;
3617 }
3618
3619 public void execute(ObbActionHandler handler) {
3620 try {
3621 if (DEBUG_OBB)
Ben Komalo444eca22011-09-01 15:17:44 -07003622 Slog.i(TAG, "Starting to execute action: " + toString());
Kenny Roota02b8b02010-08-05 16:14:17 -07003623 mRetries++;
3624 if (mRetries > MAX_RETRIES) {
3625 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
Kenny Root480afe72010-10-07 10:17:50 -07003626 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003627 handleError();
Kenny Roota02b8b02010-08-05 16:14:17 -07003628 } else {
3629 handleExecute();
3630 if (DEBUG_OBB)
3631 Slog.i(TAG, "Posting install MCS_UNBIND");
3632 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
3633 }
3634 } catch (RemoteException e) {
3635 if (DEBUG_OBB)
3636 Slog.i(TAG, "Posting install MCS_RECONNECT");
3637 mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
3638 } catch (Exception e) {
3639 if (DEBUG_OBB)
3640 Slog.d(TAG, "Error handling OBB action", e);
3641 handleError();
Kenny Root17eb6fb2010-10-06 15:02:52 -07003642 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003643 }
3644 }
3645
Kenny Root05105f72010-09-22 17:29:43 -07003646 abstract void handleExecute() throws RemoteException, IOException;
Kenny Roota02b8b02010-08-05 16:14:17 -07003647 abstract void handleError();
Kenny Root38cf8862010-09-26 14:18:51 -07003648
3649 protected ObbInfo getObbInfo() throws IOException {
3650 ObbInfo obbInfo;
3651 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003652 obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003653 } catch (RemoteException e) {
3654 Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003655 + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003656 obbInfo = null;
3657 }
3658 if (obbInfo == null) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003659 throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003660 }
3661 return obbInfo;
3662 }
3663
Kenny Rootaf9d6672010-10-08 09:21:39 -07003664 protected void sendNewStatusOrIgnore(int status) {
3665 if (mObbState == null || mObbState.token == null) {
3666 return;
3667 }
3668
Kenny Root38cf8862010-09-26 14:18:51 -07003669 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003670 mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
Kenny Root38cf8862010-09-26 14:18:51 -07003671 } catch (RemoteException e) {
Sudheer Shanka2250d562016-11-07 15:41:02 -08003672 Slog.w(TAG, "StorageEventListener went away while calling onObbStateChanged");
Kenny Root38cf8862010-09-26 14:18:51 -07003673 }
3674 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003675 }
3676
3677 class MountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003678 private final String mKey;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003679 private final int mCallingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003680
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003681 MountObbAction(ObbState obbState, String key, int callingUid) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003682 super(obbState);
3683 mKey = key;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003684 mCallingUid = callingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003685 }
3686
Jason parks5af0b912010-11-29 09:05:25 -06003687 @Override
Kenny Root735de3b2010-09-30 14:11:39 -07003688 public void handleExecute() throws IOException, RemoteException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003689 waitForReady();
3690 warnOnNotMounted();
3691
Kenny Root38cf8862010-09-26 14:18:51 -07003692 final ObbInfo obbInfo = getObbInfo();
3693
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003694 if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003695 Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
3696 + " which is owned by " + obbInfo.packageName);
3697 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3698 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003699 }
3700
Kenny Rootaf9d6672010-10-08 09:21:39 -07003701 final boolean isMounted;
3702 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003703 isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003704 }
3705 if (isMounted) {
3706 Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
3707 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
3708 return;
3709 }
3710
Kenny Rootaf9d6672010-10-08 09:21:39 -07003711 final String hashedKey;
3712 if (mKey == null) {
3713 hashedKey = "none";
3714 } else {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003715 try {
Kenny Root3b1abba2010-10-13 15:00:07 -07003716 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
3717
3718 KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
3719 PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
3720 SecretKey key = factory.generateSecret(ks);
3721 BigInteger bi = new BigInteger(key.getEncoded());
3722 hashedKey = bi.toString(16);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003723 } catch (NoSuchAlgorithmException e) {
Kenny Root3b1abba2010-10-13 15:00:07 -07003724 Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
3725 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
3726 return;
3727 } catch (InvalidKeySpecException e) {
3728 Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
3729 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root38cf8862010-09-26 14:18:51 -07003730 return;
3731 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003732 }
Kenny Root38cf8862010-09-26 14:18:51 -07003733
Kenny Rootaf9d6672010-10-08 09:21:39 -07003734 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003735 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003736 mConnector.execute("obb", "mount", mObbState.canonicalPath, new SensitiveArg(hashedKey),
Jeff Sharkey56cd6462013-06-07 15:09:15 -07003737 mObbState.ownerGid);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003738 } catch (NativeDaemonConnectorException e) {
3739 int code = e.getCode();
3740 if (code != VoldResponseCode.OpFailedStorageBusy) {
3741 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003742 }
3743 }
3744
Kenny Rootaf9d6672010-10-08 09:21:39 -07003745 if (rc == StorageResultCode.OperationSucceeded) {
3746 if (DEBUG_OBB)
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003747 Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003748
3749 synchronized (mObbMounts) {
3750 addObbStateLocked(mObbState);
3751 }
3752
3753 sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
Kenny Root02c87302010-07-01 08:10:18 -07003754 } else {
Kenny Root05105f72010-09-22 17:29:43 -07003755 Slog.e(TAG, "Couldn't mount OBB file: " + rc);
Kenny Roota02b8b02010-08-05 16:14:17 -07003756
Kenny Rootaf9d6672010-10-08 09:21:39 -07003757 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
Kenny Root02c87302010-07-01 08:10:18 -07003758 }
3759 }
3760
Jason parks5af0b912010-11-29 09:05:25 -06003761 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003762 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003763 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root02c87302010-07-01 08:10:18 -07003764 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003765
3766 @Override
3767 public String toString() {
3768 StringBuilder sb = new StringBuilder();
3769 sb.append("MountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003770 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003771 sb.append('}');
3772 return sb.toString();
3773 }
3774 }
3775
3776 class UnmountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003777 private final boolean mForceUnmount;
Kenny Roota02b8b02010-08-05 16:14:17 -07003778
3779 UnmountObbAction(ObbState obbState, boolean force) {
3780 super(obbState);
3781 mForceUnmount = force;
3782 }
3783
Jason parks5af0b912010-11-29 09:05:25 -06003784 @Override
Kenny Root38cf8862010-09-26 14:18:51 -07003785 public void handleExecute() throws IOException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003786 waitForReady();
3787 warnOnNotMounted();
3788
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003789 final ObbState existingState;
Kenny Root38cf8862010-09-26 14:18:51 -07003790 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003791 existingState = mObbPathToStateMap.get(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003792 }
Kenny Root38cf8862010-09-26 14:18:51 -07003793
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003794 if (existingState == null) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003795 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
3796 return;
3797 }
3798
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003799 if (existingState.ownerGid != mObbState.ownerGid) {
3800 Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
3801 + " (owned by GID " + existingState.ownerGid + ")");
Kenny Rootaf9d6672010-10-08 09:21:39 -07003802 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3803 return;
3804 }
3805
Kenny Rootaf9d6672010-10-08 09:21:39 -07003806 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003807 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003808 final Command cmd = new Command("obb", "unmount", mObbState.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08003809 if (mForceUnmount) {
3810 cmd.appendArg("force");
3811 }
3812 mConnector.execute(cmd);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003813 } catch (NativeDaemonConnectorException e) {
3814 int code = e.getCode();
3815 if (code == VoldResponseCode.OpFailedStorageBusy) {
3816 rc = StorageResultCode.OperationFailedStorageBusy;
3817 } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
3818 // If it's not mounted then we've already won.
3819 rc = StorageResultCode.OperationSucceeded;
3820 } else {
3821 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003822 }
3823 }
3824
Kenny Rootaf9d6672010-10-08 09:21:39 -07003825 if (rc == StorageResultCode.OperationSucceeded) {
3826 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003827 removeObbStateLocked(existingState);
Kenny Root38cf8862010-09-26 14:18:51 -07003828 }
3829
Kenny Rootaf9d6672010-10-08 09:21:39 -07003830 sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
Kenny Roota02b8b02010-08-05 16:14:17 -07003831 } else {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003832 Slog.w(TAG, "Could not unmount OBB: " + existingState);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003833 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
Kenny Roota02b8b02010-08-05 16:14:17 -07003834 }
3835 }
3836
Jason parks5af0b912010-11-29 09:05:25 -06003837 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003838 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003839 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Roota02b8b02010-08-05 16:14:17 -07003840 }
3841
3842 @Override
3843 public String toString() {
3844 StringBuilder sb = new StringBuilder();
3845 sb.append("UnmountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003846 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003847 sb.append(",force=");
3848 sb.append(mForceUnmount);
Kenny Roota02b8b02010-08-05 16:14:17 -07003849 sb.append('}');
3850 return sb.toString();
3851 }
Kenny Root02c87302010-07-01 08:10:18 -07003852 }
Kenny Root38cf8862010-09-26 14:18:51 -07003853
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003854 private static class Callbacks extends Handler {
3855 private static final int MSG_STORAGE_STATE_CHANGED = 1;
3856 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003857 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
3858 private static final int MSG_VOLUME_FORGOTTEN = 4;
3859 private static final int MSG_DISK_SCANNED = 5;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003860 private static final int MSG_DISK_DESTROYED = 6;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003861
Sudheer Shanka2250d562016-11-07 15:41:02 -08003862 private final RemoteCallbackList<IStorageEventListener>
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003863 mCallbacks = new RemoteCallbackList<>();
3864
3865 public Callbacks(Looper looper) {
3866 super(looper);
3867 }
3868
Sudheer Shanka2250d562016-11-07 15:41:02 -08003869 public void register(IStorageEventListener callback) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003870 mCallbacks.register(callback);
3871 }
3872
Sudheer Shanka2250d562016-11-07 15:41:02 -08003873 public void unregister(IStorageEventListener callback) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003874 mCallbacks.unregister(callback);
3875 }
3876
3877 @Override
3878 public void handleMessage(Message msg) {
3879 final SomeArgs args = (SomeArgs) msg.obj;
3880 final int n = mCallbacks.beginBroadcast();
3881 for (int i = 0; i < n; i++) {
Sudheer Shanka2250d562016-11-07 15:41:02 -08003882 final IStorageEventListener callback = mCallbacks.getBroadcastItem(i);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003883 try {
3884 invokeCallback(callback, msg.what, args);
3885 } catch (RemoteException ignored) {
3886 }
3887 }
3888 mCallbacks.finishBroadcast();
3889 args.recycle();
3890 }
3891
Sudheer Shanka2250d562016-11-07 15:41:02 -08003892 private void invokeCallback(IStorageEventListener callback, int what, SomeArgs args)
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003893 throws RemoteException {
3894 switch (what) {
3895 case MSG_STORAGE_STATE_CHANGED: {
3896 callback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
3897 (String) args.arg3);
3898 break;
3899 }
3900 case MSG_VOLUME_STATE_CHANGED: {
3901 callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
3902 break;
3903 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07003904 case MSG_VOLUME_RECORD_CHANGED: {
3905 callback.onVolumeRecordChanged((VolumeRecord) args.arg1);
3906 break;
3907 }
3908 case MSG_VOLUME_FORGOTTEN: {
3909 callback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003910 break;
3911 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003912 case MSG_DISK_SCANNED: {
3913 callback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003914 break;
3915 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003916 case MSG_DISK_DESTROYED: {
3917 callback.onDiskDestroyed((DiskInfo) args.arg1);
3918 break;
3919 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003920 }
3921 }
3922
3923 private void notifyStorageStateChanged(String path, String oldState, String newState) {
3924 final SomeArgs args = SomeArgs.obtain();
3925 args.arg1 = path;
3926 args.arg2 = oldState;
3927 args.arg3 = newState;
3928 obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
3929 }
3930
3931 private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
3932 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003933 args.arg1 = vol.clone();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003934 args.argi2 = oldState;
3935 args.argi3 = newState;
3936 obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
3937 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003938
Jeff Sharkey50a05452015-04-29 11:24:52 -07003939 private void notifyVolumeRecordChanged(VolumeRecord rec) {
3940 final SomeArgs args = SomeArgs.obtain();
3941 args.arg1 = rec.clone();
3942 obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
3943 }
3944
3945 private void notifyVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003946 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003947 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003948 obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003949 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003950
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003951 private void notifyDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003952 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003953 args.arg1 = disk.clone();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003954 args.argi2 = volumeCount;
3955 obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003956 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003957
3958 private void notifyDiskDestroyed(DiskInfo disk) {
3959 final SomeArgs args = SomeArgs.obtain();
3960 args.arg1 = disk.clone();
3961 obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
3962 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003963 }
3964
Kenny Root38cf8862010-09-26 14:18:51 -07003965 @Override
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003966 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003967 if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003968
3969 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003970 synchronized (mLock) {
3971 pw.println("Disks:");
3972 pw.increaseIndent();
3973 for (int i = 0; i < mDisks.size(); i++) {
3974 final DiskInfo disk = mDisks.valueAt(i);
3975 disk.dump(pw);
3976 }
3977 pw.decreaseIndent();
3978
3979 pw.println();
3980 pw.println("Volumes:");
3981 pw.increaseIndent();
3982 for (int i = 0; i < mVolumes.size(); i++) {
3983 final VolumeInfo vol = mVolumes.valueAt(i);
3984 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue;
3985 vol.dump(pw);
3986 }
3987 pw.decreaseIndent();
3988
3989 pw.println();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003990 pw.println("Records:");
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003991 pw.increaseIndent();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003992 for (int i = 0; i < mRecords.size(); i++) {
3993 final VolumeRecord note = mRecords.valueAt(i);
3994 note.dump(pw);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003995 }
3996 pw.decreaseIndent();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07003997
3998 pw.println();
3999 pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
Felipe Leme281389a2016-10-10 17:12:20 -07004000 final Pair<String, Long> pair = StorageManager.getPrimaryStoragePathAndSize();
4001 if (pair == null) {
4002 pw.println("Internal storage total size: N/A");
4003 } else {
4004 pw.print("Internal storage (");
4005 pw.print(pair.first);
4006 pw.print(") total size: ");
4007 pw.print(pair.second);
4008 pw.print(" (");
4009 pw.print((float) pair.second / TrafficStats.GB_IN_BYTES);
4010 pw.println(" GB)");
4011 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07004012 pw.println("Force adoptable: " + mForceAdoptable);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08004013 pw.println();
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07004014 pw.println("Local unlocked users: " + Arrays.toString(mLocalUnlockedUsers));
4015 pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
Jeff Sharkey27de30d2015-04-18 16:20:27 -07004016 }
Kenny Root38cf8862010-09-26 14:18:51 -07004017
Kenny Root38cf8862010-09-26 14:18:51 -07004018 synchronized (mObbMounts) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07004019 pw.println();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004020 pw.println("mObbMounts:");
4021 pw.increaseIndent();
4022 final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet()
4023 .iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07004024 while (binders.hasNext()) {
4025 Entry<IBinder, List<ObbState>> e = binders.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004026 pw.println(e.getKey() + ":");
4027 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07004028 final List<ObbState> obbStates = e.getValue();
Kenny Root38cf8862010-09-26 14:18:51 -07004029 for (final ObbState obbState : obbStates) {
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004030 pw.println(obbState);
Kenny Root38cf8862010-09-26 14:18:51 -07004031 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004032 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07004033 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004034 pw.decreaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07004035
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004036 pw.println();
4037 pw.println("mObbPathToStateMap:");
4038 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07004039 final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
4040 while (maps.hasNext()) {
4041 final Entry<String, ObbState> e = maps.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004042 pw.print(e.getKey());
4043 pw.print(" -> ");
4044 pw.println(e.getValue());
Kenny Rootaf9d6672010-10-08 09:21:39 -07004045 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004046 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07004047 }
Kenny Root4161f9b2011-07-13 09:48:33 -07004048
Robert Greenwalt470fd722012-01-18 12:51:15 -08004049 pw.println();
Jeff Sharkey5b0e5202015-12-18 17:18:09 -07004050 pw.println("mConnector:");
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004051 pw.increaseIndent();
Robert Greenwalt470fd722012-01-18 12:51:15 -08004052 mConnector.dump(fd, pw, args);
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004053 pw.decreaseIndent();
Christopher Tate7265abe2014-11-21 13:54:45 -08004054
Christopher Tate7265abe2014-11-21 13:54:45 -08004055 pw.println();
Jeff Sharkey5b0e5202015-12-18 17:18:09 -07004056 pw.println("mCryptConnector:");
4057 pw.increaseIndent();
4058 mCryptConnector.dump(fd, pw, args);
4059 pw.decreaseIndent();
4060
4061 pw.println();
Christopher Tate7265abe2014-11-21 13:54:45 -08004062 pw.print("Last maintenance: ");
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07004063 pw.println(TimeUtils.formatForLogging(mLastMaintenance));
Kenny Root38cf8862010-09-26 14:18:51 -07004064 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004065
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07004066 /** {@inheritDoc} */
Jeff Sharkey48877892015-03-18 11:27:19 -07004067 @Override
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07004068 public void monitor() {
4069 if (mConnector != null) {
4070 mConnector.monitor();
4071 }
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07004072 if (mCryptConnector != null) {
4073 mCryptConnector.monitor();
4074 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07004075 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07004076
Sudheer Shanka2250d562016-11-07 15:41:02 -08004077 private final class StorageManagerInternalImpl extends StorageManagerInternal {
Svet Ganov6ee871e2015-07-10 14:29:33 -07004078 // Not guarded by a lock.
4079 private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
4080 new CopyOnWriteArrayList<>();
4081
4082 @Override
4083 public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
4084 // No locking - CopyOnWriteArrayList
4085 mPolicies.add(policy);
4086 }
4087
4088 @Override
4089 public void onExternalStoragePolicyChanged(int uid, String packageName) {
4090 final int mountMode = getExternalStorageMountMode(uid, packageName);
4091 remountUidExternalStorage(uid, mountMode);
4092 }
4093
4094 @Override
4095 public int getExternalStorageMountMode(int uid, String packageName) {
4096 // No locking - CopyOnWriteArrayList
4097 int mountMode = Integer.MAX_VALUE;
4098 for (ExternalStorageMountPolicy policy : mPolicies) {
4099 final int policyMode = policy.getMountMode(uid, packageName);
4100 if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
4101 return Zygote.MOUNT_EXTERNAL_NONE;
4102 }
4103 mountMode = Math.min(mountMode, policyMode);
4104 }
4105 if (mountMode == Integer.MAX_VALUE) {
4106 return Zygote.MOUNT_EXTERNAL_NONE;
4107 }
4108 return mountMode;
4109 }
4110
4111 public boolean hasExternalStorage(int uid, String packageName) {
Amith Yamasani2bd5cff2015-07-22 14:42:31 -07004112 // No need to check for system uid. This avoids a deadlock between
4113 // PackageManagerService and AppOpsService.
4114 if (uid == Process.SYSTEM_UID) {
4115 return true;
4116 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07004117 // No locking - CopyOnWriteArrayList
4118 for (ExternalStorageMountPolicy policy : mPolicies) {
4119 final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
4120 if (!policyHasStorage) {
4121 return false;
4122 }
4123 }
4124 return true;
4125 }
4126 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07004127}