blob: ec05dae68a85f0d8bd4516b0a76004cbcf097a1a [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;
Elliott Hughesf839b4f2014-09-26 12:30:47 -070034import android.app.ActivityManagerNative;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -070035import android.app.AppOpsManager;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070036import android.app.IActivityManager;
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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.net.Uri;
Kenny Root02c87302010-07-01 08:10:18 -070050import android.os.Binder;
Jeff Sharkey4c099d02015-05-15 13:45:00 -070051import android.os.DropBoxManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070052import android.os.Environment;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070053import android.os.Environment.UserEnvironment;
Jeff Sharkey48877892015-03-18 11:27:19 -070054import android.os.FileUtils;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080055import android.os.Handler;
Dianne Hackbornefa92b22013-05-03 14:11:43 -070056import android.os.HandlerThread;
Kenny Roota02b8b02010-08-05 16:14:17 -070057import android.os.IBinder;
Daniel Sandler5f27ef42010-03-16 15:42:02 -040058import android.os.Looper;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080059import android.os.Message;
Daichi Hirono9e8d9e22015-11-13 14:37:00 +090060import android.os.ParcelFileDescriptor;
Jeff Sharkeyce14cd02015-12-07 15:35:42 -070061import android.os.PowerManager;
Jeff Sharkey9527b222015-06-24 15:24:48 -070062import android.os.Process;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070063import android.os.RemoteCallbackList;
San Mehat4270e1e2010-01-29 05:32:19 -080064import android.os.RemoteException;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -080065import android.os.ServiceManager;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -070066import android.os.SystemClock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070068import android.os.UserHandle;
Emily Bernier92aa5a22014-07-07 10:11:48 -040069import android.os.UserManager;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070070import android.os.storage.DiskInfo;
Kenny Roota02b8b02010-08-05 16:14:17 -070071import android.os.storage.IMountService;
72import android.os.storage.IMountServiceListener;
73import android.os.storage.IMountShutdownObserver;
74import android.os.storage.IObbActionListener;
Svet Ganov6ee871e2015-07-10 14:29:33 -070075import android.os.storage.MountServiceInternal;
Kenny Rootaf9d6672010-10-08 09:21:39 -070076import android.os.storage.OnObbStateChangeListener;
Paul Lawrence46791e72014-04-03 09:10:26 -070077import android.os.storage.StorageManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070078import android.os.storage.StorageResultCode;
Mike Lockwood2f6a3882011-05-09 19:08:06 -070079import android.os.storage.StorageVolume;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070080import android.os.storage.VolumeInfo;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070081import android.os.storage.VolumeRecord;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070082import android.provider.MediaStore;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070083import android.provider.Settings;
Jason parksf7b3cd42011-01-27 09:28:25 -060084import android.text.TextUtils;
Jeff Sharkey1783f142015-04-17 10:52:51 -070085import android.text.format.DateUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -070086import android.util.ArrayMap;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070087import android.util.AtomicFile;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070088import android.util.Log;
San Mehata5078592010-03-25 09:36:54 -070089import android.util.Slog;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070090import android.util.TimeUtils;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070091import android.util.Xml;
Jeff Sharkey48877892015-03-18 11:27:19 -070092
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -080093import com.android.internal.annotations.GuardedBy;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070094import com.android.internal.app.IMediaContainerService;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070095import com.android.internal.os.SomeArgs;
Jeff Sharkey9527b222015-06-24 15:24:48 -070096import com.android.internal.os.Zygote;
Jeff Sharkey48877892015-03-18 11:27:19 -070097import com.android.internal.util.ArrayUtils;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070098import com.android.internal.util.FastXmlSerializer;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -080099import com.android.internal.util.HexDump;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -0700100import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700101import com.android.internal.util.Preconditions;
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700102import com.android.internal.widget.LockPatternUtils;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700103import com.android.server.NativeDaemonConnector.Command;
Jeff Sharkey56cd6462013-06-07 15:09:15 -0700104import com.android.server.NativeDaemonConnector.SensitiveArg;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700105import com.android.server.pm.PackageManagerService;
Kenny Roota02b8b02010-08-05 16:14:17 -0700106
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700107import libcore.io.IoUtils;
108import libcore.util.EmptyArray;
109
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700110import org.xmlpull.v1.XmlPullParser;
111import org.xmlpull.v1.XmlPullParserException;
112import org.xmlpull.v1.XmlSerializer;
113
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700114import java.io.File;
Kenny Root38cf8862010-09-26 14:18:51 -0700115import java.io.FileDescriptor;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700116import java.io.FileInputStream;
117import java.io.FileNotFoundException;
Christopher Tate7265abe2014-11-21 13:54:45 -0800118import java.io.FileOutputStream;
Kenny Root05105f72010-09-22 17:29:43 -0700119import java.io.IOException;
Kenny Root38cf8862010-09-26 14:18:51 -0700120import java.io.PrintWriter;
Kenny Root3b1abba2010-10-13 15:00:07 -0700121import java.math.BigInteger;
Paul Lawrence8e397362014-01-27 15:22:30 -0800122import java.nio.charset.StandardCharsets;
Kenny Root735de3b2010-09-30 14:11:39 -0700123import java.security.NoSuchAlgorithmException;
Kenny Root3b1abba2010-10-13 15:00:07 -0700124import java.security.spec.InvalidKeySpecException;
125import java.security.spec.KeySpec;
San Mehat22dd86e2010-01-12 12:21:18 -0800126import java.util.ArrayList;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800127import java.util.Arrays;
Kenny Roota02b8b02010-08-05 16:14:17 -0700128import java.util.HashMap;
San Mehat6cdd9c02010-02-09 14:45:20 -0800129import java.util.HashSet;
Kenny Root38cf8862010-09-26 14:18:51 -0700130import java.util.Iterator;
Kenny Roota02b8b02010-08-05 16:14:17 -0700131import java.util.LinkedList;
132import java.util.List;
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700133import java.util.Locale;
Kenny Roota02b8b02010-08-05 16:14:17 -0700134import java.util.Map;
Kenny Root38cf8862010-09-26 14:18:51 -0700135import java.util.Map.Entry;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700136import java.util.Objects;
Svet Ganov6ee871e2015-07-10 14:29:33 -0700137import java.util.concurrent.CopyOnWriteArrayList;
Kenny Root51a573c2012-05-17 13:30:28 -0700138import java.util.concurrent.CountDownLatch;
139import java.util.concurrent.TimeUnit;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700140import java.util.concurrent.TimeoutException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141
Kenny Root3b1abba2010-10-13 15:00:07 -0700142import javax.crypto.SecretKey;
143import javax.crypto.SecretKeyFactory;
144import javax.crypto.spec.PBEKeySpec;
145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146/**
Jeff Sharkey48877892015-03-18 11:27:19 -0700147 * Service responsible for various storage media. Connects to {@code vold} to
148 * watch for and manage dynamically added storage, such as SD cards and USB mass
149 * storage. Also decides how storage should be presented to users on the device.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 */
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700151class MountService extends IMountService.Stub
152 implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
Jason parks5af0b912010-11-29 09:05:25 -0600153
Christopher Tated417d622013-08-19 16:14:25 -0700154 // Static direct instance pointer for the tightly-coupled idle service to use
155 static MountService sSelf = null;
156
Jeff Sharkey56e62932015-03-21 20:41:00 -0700157 public static class Lifecycle extends SystemService {
158 private MountService mMountService;
159
160 public Lifecycle(Context context) {
161 super(context);
162 }
163
164 @Override
165 public void onStart() {
166 mMountService = new MountService(getContext());
167 publishBinderService("mount", mMountService);
Jeff Sharkeycd575992016-03-29 14:12:49 -0600168 mMountService.start();
Jeff Sharkey56e62932015-03-21 20:41:00 -0700169 }
170
171 @Override
172 public void onBootPhase(int phase) {
173 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
174 mMountService.systemReady();
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900175 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
176 mMountService.bootCompleted();
Jeff Sharkey56e62932015-03-21 20:41:00 -0700177 }
178 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700179
180 @Override
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700181 public void onUnlockUser(int userHandle) {
182 mMountService.onUnlockUser(userHandle);
Jeff Sharkey48877892015-03-18 11:27:19 -0700183 }
184
185 @Override
186 public void onCleanupUser(int userHandle) {
187 mMountService.onCleanupUser(userHandle);
188 }
Jeff Sharkey56e62932015-03-21 20:41:00 -0700189 }
190
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800191 private static final boolean DEBUG_EVENTS = false;
Kenny Rootb7db2722011-01-25 16:39:35 -0800192 private static final boolean DEBUG_OBB = false;
Kenny Root02c87302010-07-01 08:10:18 -0700193
Kenny Root07714d42011-08-17 17:49:28 -0700194 // Disable this since it messes up long-running cryptfs operations.
195 private static final boolean WATCHDOG_ENABLE = false;
196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 private static final String TAG = "MountService";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700198
Jeff Sharkey9756d752015-05-14 21:07:42 -0700199 private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700200 private static final String TAG_STORAGE_TRIM = "storage_trim";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201
Kenny Root305bcbf2010-09-03 07:56:38 -0700202 private static final String VOLD_TAG = "VoldConnector";
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700203 private static final String CRYPTD_TAG = "CryptdConnector";
Kenny Root305bcbf2010-09-03 07:56:38 -0700204
Kenny Rootcf0b38c2011-03-22 14:17:59 -0700205 /** Maximum number of ASEC containers allowed to be mounted. */
206 private static final int MAX_CONTAINERS = 250;
207
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700208 /** Magic value sent by MoveTask.cpp */
209 private static final int MOVE_STATUS_COPY_FINISHED = 82;
210
San Mehat4270e1e2010-01-29 05:32:19 -0800211 /*
212 * Internal vold response code constants
213 */
San Mehat22dd86e2010-01-12 12:21:18 -0800214 class VoldResponseCode {
San Mehat4270e1e2010-01-29 05:32:19 -0800215 /*
216 * 100 series - Requestion action was initiated; expect another reply
217 * before proceeding with a new command.
218 */
San Mehat22dd86e2010-01-12 12:21:18 -0800219 public static final int VolumeListResult = 110;
220 public static final int AsecListResult = 111;
San Mehatc1b4ce92010-02-16 17:13:03 -0800221 public static final int StorageUsersListResult = 112;
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700222 public static final int CryptfsGetfieldResult = 113;
San Mehat22dd86e2010-01-12 12:21:18 -0800223
San Mehat4270e1e2010-01-29 05:32:19 -0800224 /*
225 * 200 series - Requestion action has been successfully completed.
226 */
227 public static final int ShareStatusResult = 210;
San Mehat22dd86e2010-01-12 12:21:18 -0800228 public static final int AsecPathResult = 211;
San Mehat4270e1e2010-01-29 05:32:19 -0800229 public static final int ShareEnabledResult = 212;
San Mehat22dd86e2010-01-12 12:21:18 -0800230
San Mehat4270e1e2010-01-29 05:32:19 -0800231 /*
232 * 400 series - Command was accepted, but the requested action
233 * did not take place.
234 */
235 public static final int OpFailedNoMedia = 401;
236 public static final int OpFailedMediaBlank = 402;
237 public static final int OpFailedMediaCorrupt = 403;
238 public static final int OpFailedVolNotMounted = 404;
San Mehatd9709982010-02-18 11:43:03 -0800239 public static final int OpFailedStorageBusy = 405;
San Mehat2d66cef2010-03-23 11:12:52 -0700240 public static final int OpFailedStorageNotFound = 406;
San Mehat4270e1e2010-01-29 05:32:19 -0800241
242 /*
243 * 600 series - Unsolicited broadcasts.
244 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700245 public static final int DISK_CREATED = 640;
246 public static final int DISK_SIZE_CHANGED = 641;
247 public static final int DISK_LABEL_CHANGED = 642;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700248 public static final int DISK_SCANNED = 643;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700249 public static final int DISK_SYS_PATH_CHANGED = 644;
Jeff Sharkey48877892015-03-18 11:27:19 -0700250 public static final int DISK_DESTROYED = 649;
251
252 public static final int VOLUME_CREATED = 650;
253 public static final int VOLUME_STATE_CHANGED = 651;
254 public static final int VOLUME_FS_TYPE_CHANGED = 652;
255 public static final int VOLUME_FS_UUID_CHANGED = 653;
256 public static final int VOLUME_FS_LABEL_CHANGED = 654;
257 public static final int VOLUME_PATH_CHANGED = 655;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700258 public static final int VOLUME_INTERNAL_PATH_CHANGED = 656;
Jeff Sharkey48877892015-03-18 11:27:19 -0700259 public static final int VOLUME_DESTROYED = 659;
Svetoslavf23b64d2013-04-25 14:45:54 -0700260
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700261 public static final int MOVE_STATUS = 660;
Jeff Sharkey9756d752015-05-14 21:07:42 -0700262 public static final int BENCHMARK_RESULT = 661;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700263 public static final int TRIM_RESULT = 662;
San Mehat22dd86e2010-01-12 12:21:18 -0800264 }
265
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700266 private static final int VERSION_INIT = 1;
267 private static final int VERSION_ADD_PRIMARY = 2;
Jeff Sharkeyfced5342015-05-10 14:53:34 -0700268 private static final int VERSION_FIX_PRIMARY = 3;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700269
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700270 private static final String TAG_VOLUMES = "volumes";
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700271 private static final String ATTR_VERSION = "version";
272 private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid";
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700273 private static final String ATTR_FORCE_ADOPTABLE = "forceAdoptable";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700274 private static final String TAG_VOLUME = "volume";
275 private static final String ATTR_TYPE = "type";
276 private static final String ATTR_FS_UUID = "fsUuid";
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700277 private static final String ATTR_PART_GUID = "partGuid";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700278 private static final String ATTR_NICKNAME = "nickname";
279 private static final String ATTR_USER_FLAGS = "userFlags";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700280 private static final String ATTR_CREATED_MILLIS = "createdMillis";
281 private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis";
282 private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700283
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700284 private final AtomicFile mSettingsFile;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700285
Jeff Sharkey48877892015-03-18 11:27:19 -0700286 /**
287 * <em>Never</em> hold the lock while performing downcalls into vold, since
288 * unsolicited events can suddenly appear to update data structures.
289 */
290 private final Object mLock = new Object();
291
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700292 /** Set of users that we know are unlocked. */
Jeff Sharkey48877892015-03-18 11:27:19 -0700293 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700294 private int[] mLocalUnlockedUsers = EmptyArray.INT;
295 /** Set of users that system knows are unlocked. */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800296 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700297 private int[] mSystemUnlockedUsers = EmptyArray.INT;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700298
299 /** Map from disk ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700300 @GuardedBy("mLock")
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700301 private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700302 /** Map from volume ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700303 @GuardedBy("mLock")
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700304 private final ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
Jeff Sharkey48877892015-03-18 11:27:19 -0700305
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700306 /** Map from UUID to record */
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700307 @GuardedBy("mLock")
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700308 private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>();
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700309 @GuardedBy("mLock")
310 private String mPrimaryStorageUuid;
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700311 @GuardedBy("mLock")
312 private boolean mForceAdoptable;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700313
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700314 /** Map from disk ID to latches */
315 @GuardedBy("mLock")
316 private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
317
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700318 @GuardedBy("mLock")
319 private IPackageMoveObserver mMoveCallback;
320 @GuardedBy("mLock")
321 private String mMoveTargetUuid;
322
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700323 private VolumeInfo findVolumeByIdOrThrow(String id) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700324 synchronized (mLock) {
325 final VolumeInfo vol = mVolumes.get(id);
326 if (vol != null) {
327 return vol;
328 }
329 }
330 throw new IllegalArgumentException("No volume found for ID " + id);
331 }
332
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700333 private String findVolumeIdForPathOrThrow(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700334 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700335 for (int i = 0; i < mVolumes.size(); i++) {
336 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700337 if (vol.path != null && path.startsWith(vol.path)) {
338 return vol.id;
Jeff Sharkey48877892015-03-18 11:27:19 -0700339 }
340 }
341 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700342 throw new IllegalArgumentException("No volume found for path " + path);
Jeff Sharkey48877892015-03-18 11:27:19 -0700343 }
344
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700345 private VolumeRecord findRecordForPath(String path) {
346 synchronized (mLock) {
347 for (int i = 0; i < mVolumes.size(); i++) {
348 final VolumeInfo vol = mVolumes.valueAt(i);
349 if (vol.path != null && path.startsWith(vol.path)) {
350 return mRecords.get(vol.fsUuid);
351 }
352 }
353 }
354 return null;
355 }
356
357 private String scrubPath(String path) {
358 if (path.startsWith(Environment.getDataDirectory().getAbsolutePath())) {
359 return "internal";
360 }
361 final VolumeRecord rec = findRecordForPath(path);
362 if (rec == null || rec.createdMillis == 0) {
363 return "unknown";
364 } else {
365 return "ext:" + (int) ((System.currentTimeMillis() - rec.createdMillis)
366 / DateUtils.WEEK_IN_MILLIS) + "w";
367 }
368 }
369
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700370 private @Nullable VolumeInfo findStorageForUuid(String volumeUuid) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700371 final StorageManager storage = mContext.getSystemService(StorageManager.class);
372 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700373 return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL);
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700374 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
375 return storage.getPrimaryPhysicalVolume();
376 } else {
377 return storage.findEmulatedForPrivate(storage.findVolumeByUuid(volumeUuid));
378 }
379 }
380
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700381 private boolean shouldBenchmark() {
382 final long benchInterval = Settings.Global.getLong(mContext.getContentResolver(),
383 Settings.Global.STORAGE_BENCHMARK_INTERVAL, DateUtils.WEEK_IN_MILLIS);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700384 if (benchInterval == -1) {
385 return false;
386 } else if (benchInterval == 0) {
387 return true;
388 }
389
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700390 synchronized (mLock) {
391 for (int i = 0; i < mVolumes.size(); i++) {
392 final VolumeInfo vol = mVolumes.valueAt(i);
393 final VolumeRecord rec = mRecords.get(vol.fsUuid);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700394 if (vol.isMountedWritable() && rec != null) {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700395 final long benchAge = System.currentTimeMillis() - rec.lastBenchMillis;
396 if (benchAge >= benchInterval) {
397 return true;
398 }
399 }
400 }
401 return false;
402 }
403 }
404
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700405 private CountDownLatch findOrCreateDiskScanLatch(String diskId) {
406 synchronized (mLock) {
407 CountDownLatch latch = mDiskScanLatches.get(diskId);
408 if (latch == null) {
409 latch = new CountDownLatch(1);
410 mDiskScanLatches.put(diskId, latch);
411 }
412 return latch;
413 }
414 }
415
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800416 private static String escapeNull(String arg) {
417 if (TextUtils.isEmpty(arg)) {
418 return "!";
419 } else {
420 if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
421 throw new IllegalArgumentException(arg);
422 }
423 return arg;
424 }
425 }
426
Paul Lawrence8e397362014-01-27 15:22:30 -0800427 /** List of crypto types.
428 * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
429 * corresponding commands in CommandListener.cpp */
430 public static final String[] CRYPTO_TYPES
431 = { "password", "default", "pattern", "pin" };
432
Brian Carlstrom7395a8a2014-04-28 22:11:01 -0700433 private final Context mContext;
Jeff Sharkeycd575992016-03-29 14:12:49 -0600434
Brian Carlstromdfad99a2014-05-07 15:21:14 -0700435 private final NativeDaemonConnector mConnector;
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700436 private final NativeDaemonConnector mCryptConnector;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700437
Jeff Sharkeycd575992016-03-29 14:12:49 -0600438 private final Thread mConnectorThread;
439 private final Thread mCryptConnectorThread;
440
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700441 private volatile boolean mSystemReady = false;
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900442 private volatile boolean mBootCompleted = false;
Jeff Sharkey48877892015-03-18 11:27:19 -0700443 private volatile boolean mDaemonConnected = false;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700444
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700445 private PackageManagerService mPms;
446
447 private final Callbacks mCallbacks;
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700448 private final LockPatternUtils mLockPatternUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -0700449
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700450 // Two connectors - mConnector & mCryptConnector
451 private final CountDownLatch mConnectedSignal = new CountDownLatch(2);
Jeff Sharkey0be607c2012-11-14 14:39:19 -0800452 private final CountDownLatch mAsecsScanned = new CountDownLatch(1);
Jeff Sharkey48877892015-03-18 11:27:19 -0700453
454 private final Object mUnmountLock = new Object();
455 @GuardedBy("mUnmountLock")
456 private CountDownLatch mUnmountSignal;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800457
San Mehat6cdd9c02010-02-09 14:45:20 -0800458 /**
459 * Private hash of currently mounted secure containers.
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800460 * Used as a lock in methods to manipulate secure containers.
San Mehat6cdd9c02010-02-09 14:45:20 -0800461 */
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800462 final private HashSet<String> mAsecMountSet = new HashSet<String>();
San Mehat6cdd9c02010-02-09 14:45:20 -0800463
Kenny Root02c87302010-07-01 08:10:18 -0700464 /**
Kenny Root3b1abba2010-10-13 15:00:07 -0700465 * The size of the crypto algorithm key in bits for OBB files. Currently
466 * Twofish is used which takes 128-bit keys.
467 */
468 private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
469
470 /**
471 * The number of times to run SHA1 in the PBKDF2 function for OBB files.
472 * 1024 is reasonably secure and not too slow.
473 */
474 private static final int PBKDF2_HASH_ROUNDS = 1024;
475
476 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700477 * Mounted OBB tracking information. Used to track the current state of all
478 * OBBs.
Kenny Root02c87302010-07-01 08:10:18 -0700479 */
Kenny Root735de3b2010-09-30 14:11:39 -0700480 final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700481
482 /** Map from raw paths to {@link ObbState}. */
Kenny Roota02b8b02010-08-05 16:14:17 -0700483 final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
484
Svet Ganov6ee871e2015-07-10 14:29:33 -0700485 // Not guarded by a lock.
486 private final MountServiceInternalImpl mMountServiceInternal = new MountServiceInternalImpl();
487
Kenny Roota02b8b02010-08-05 16:14:17 -0700488 class ObbState implements IBinder.DeathRecipient {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700489 public ObbState(String rawPath, String canonicalPath, int callingUid,
490 IObbActionListener token, int nonce) {
491 this.rawPath = rawPath;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700492 this.canonicalPath = canonicalPath;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700493
494 this.ownerGid = UserHandle.getSharedAppGid(callingUid);
Kenny Rootaf9d6672010-10-08 09:21:39 -0700495 this.token = token;
496 this.nonce = nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700497 }
498
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700499 final String rawPath;
500 final String canonicalPath;
Kenny Roota02b8b02010-08-05 16:14:17 -0700501
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700502 final int ownerGid;
Kenny Roota02b8b02010-08-05 16:14:17 -0700503
Kenny Rootaf9d6672010-10-08 09:21:39 -0700504 // Token of remote Binder caller
505 final IObbActionListener token;
506
507 // Identifier to pass back to the token
508 final int nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700509
Kenny Root735de3b2010-09-30 14:11:39 -0700510 public IBinder getBinder() {
511 return token.asBinder();
512 }
513
Kenny Roota02b8b02010-08-05 16:14:17 -0700514 @Override
515 public void binderDied() {
516 ObbAction action = new UnmountObbAction(this, true);
517 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root735de3b2010-09-30 14:11:39 -0700518 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700519
Kenny Root5919ac62010-10-05 09:49:40 -0700520 public void link() throws RemoteException {
521 getBinder().linkToDeath(this, 0);
522 }
523
524 public void unlink() {
Kenny Root735de3b2010-09-30 14:11:39 -0700525 getBinder().unlinkToDeath(this, 0);
Kenny Roota02b8b02010-08-05 16:14:17 -0700526 }
Kenny Root38cf8862010-09-26 14:18:51 -0700527
528 @Override
529 public String toString() {
530 StringBuilder sb = new StringBuilder("ObbState{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700531 sb.append("rawPath=").append(rawPath);
532 sb.append(",canonicalPath=").append(canonicalPath);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700533 sb.append(",ownerGid=").append(ownerGid);
534 sb.append(",token=").append(token);
535 sb.append(",binder=").append(getBinder());
Kenny Root38cf8862010-09-26 14:18:51 -0700536 sb.append('}');
537 return sb.toString();
538 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700539 }
540
541 // OBB Action Handler
542 final private ObbActionHandler mObbActionHandler;
543
544 // OBB action handler messages
545 private static final int OBB_RUN_ACTION = 1;
546 private static final int OBB_MCS_BOUND = 2;
547 private static final int OBB_MCS_UNBIND = 3;
548 private static final int OBB_MCS_RECONNECT = 4;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700549 private static final int OBB_FLUSH_MOUNT_STATE = 5;
Kenny Roota02b8b02010-08-05 16:14:17 -0700550
551 /*
552 * Default Container Service information
553 */
554 static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
555 "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
556
557 final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
558
559 class DefaultContainerConnection implements ServiceConnection {
Jeff Sharkey48877892015-03-18 11:27:19 -0700560 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700561 public void onServiceConnected(ComponentName name, IBinder service) {
562 if (DEBUG_OBB)
563 Slog.i(TAG, "onServiceConnected");
564 IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
565 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
566 }
567
Jeff Sharkey48877892015-03-18 11:27:19 -0700568 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700569 public void onServiceDisconnected(ComponentName name) {
570 if (DEBUG_OBB)
571 Slog.i(TAG, "onServiceDisconnected");
572 }
573 };
574
575 // Used in the ObbActionHandler
576 private IMediaContainerService mContainerService = null;
Kenny Root02c87302010-07-01 08:10:18 -0700577
Christopher Tate7265abe2014-11-21 13:54:45 -0800578 // Last fstrim operation tracking
579 private static final String LAST_FSTRIM_FILE = "last-fstrim";
580 private final File mLastMaintenanceFile;
581 private long mLastMaintenance;
582
Kenny Root02c87302010-07-01 08:10:18 -0700583 // Handler messages
Jeff Sharkey48877892015-03-18 11:27:19 -0700584 private static final int H_SYSTEM_READY = 1;
585 private static final int H_DAEMON_CONNECTED = 2;
586 private static final int H_SHUTDOWN = 3;
587 private static final int H_FSTRIM = 4;
588 private static final int H_VOLUME_MOUNT = 5;
589 private static final int H_VOLUME_BROADCAST = 6;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700590 private static final int H_INTERNAL_BROADCAST = 7;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700591 private static final int H_VOLUME_UNMOUNT = 8;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800592 private static final int H_PARTITION_FORGET = 9;
593 private static final int H_RESET = 10;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800594
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400595 class MountServiceHandler extends Handler {
Jeff Sharkey48877892015-03-18 11:27:19 -0700596 public MountServiceHandler(Looper looper) {
597 super(looper);
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400598 }
599
Jason parks5af0b912010-11-29 09:05:25 -0600600 @Override
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800601 public void handleMessage(Message msg) {
602 switch (msg.what) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700603 case H_SYSTEM_READY: {
Jeff Sharkey48877892015-03-18 11:27:19 -0700604 handleSystemReady();
605 break;
606 }
607 case H_DAEMON_CONNECTED: {
608 handleDaemonConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700609 break;
610 }
Christopher Tated417d622013-08-19 16:14:25 -0700611 case H_FSTRIM: {
Jeff Sharkey1783f142015-04-17 10:52:51 -0700612 if (!isReady()) {
613 Slog.i(TAG, "fstrim requested, but no daemon connection yet; trying again");
Christopher Tate7618db12015-04-28 16:32:55 -0700614 sendMessageDelayed(obtainMessage(H_FSTRIM, msg.obj),
615 DateUtils.SECOND_IN_MILLIS);
616 break;
Jeff Sharkey1783f142015-04-17 10:52:51 -0700617 }
618
Christopher Tated417d622013-08-19 16:14:25 -0700619 Slog.i(TAG, "Running fstrim idle maintenance");
Christopher Tate7265abe2014-11-21 13:54:45 -0800620
621 // Remember when we kicked it off
622 try {
623 mLastMaintenance = System.currentTimeMillis();
624 mLastMaintenanceFile.setLastModified(mLastMaintenance);
625 } catch (Exception e) {
626 Slog.e(TAG, "Unable to record last fstrim!");
627 }
628
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700629 final boolean shouldBenchmark = shouldBenchmark();
Christopher Tated417d622013-08-19 16:14:25 -0700630 try {
631 // This method must be run on the main (handler) thread,
632 // so it is safe to directly call into vold.
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700633 mConnector.execute("fstrim", shouldBenchmark ? "dotrimbench" : "dotrim");
Christopher Tated417d622013-08-19 16:14:25 -0700634 } catch (NativeDaemonConnectorException ndce) {
635 Slog.e(TAG, "Failed to run fstrim!");
636 }
Christopher Tate7265abe2014-11-21 13:54:45 -0800637
Christopher Tated417d622013-08-19 16:14:25 -0700638 // invoke the completion callback, if any
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700639 // TODO: fstrim is non-blocking, so remove this useless callback
Christopher Tated417d622013-08-19 16:14:25 -0700640 Runnable callback = (Runnable) msg.obj;
641 if (callback != null) {
642 callback.run();
643 }
644 break;
645 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700646 case H_SHUTDOWN: {
647 final IMountShutdownObserver obs = (IMountShutdownObserver) msg.obj;
648 boolean success = false;
649 try {
650 success = mConnector.execute("volume", "shutdown").isClassOk();
651 } catch (NativeDaemonConnectorException ignored) {
652 }
653 if (obs != null) {
654 try {
655 obs.onShutDownComplete(success ? 0 : -1);
656 } catch (RemoteException ignored) {
657 }
658 }
659 break;
660 }
661 case H_VOLUME_MOUNT: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700662 final VolumeInfo vol = (VolumeInfo) msg.obj;
Jeff Sharkey2e606d72015-07-27 14:19:54 -0700663 if (isMountDisallowed(vol)) {
664 Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");
665 break;
666 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700667 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700668 mConnector.execute("volume", "mount", vol.id, vol.mountFlags,
669 vol.mountUserId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700670 } catch (NativeDaemonConnectorException ignored) {
671 }
672 break;
673 }
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700674 case H_VOLUME_UNMOUNT: {
675 final VolumeInfo vol = (VolumeInfo) msg.obj;
676 unmount(vol.getId());
677 break;
678 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700679 case H_VOLUME_BROADCAST: {
680 final StorageVolume userVol = (StorageVolume) msg.obj;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700681 final String envState = userVol.getState();
682 Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + envState + " to "
Jeff Sharkey48877892015-03-18 11:27:19 -0700683 + userVol.getOwner());
684
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700685 final String action = VolumeInfo.getBroadcastForEnvironment(envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700686 if (action != null) {
687 final Intent intent = new Intent(action,
688 Uri.fromFile(userVol.getPathFile()));
689 intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, userVol);
690 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
691 mContext.sendBroadcastAsUser(intent, userVol.getOwner());
692 }
693 break;
694 }
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700695 case H_INTERNAL_BROADCAST: {
696 // Internal broadcasts aimed at system components, not for
697 // third-party apps.
698 final Intent intent = (Intent) msg.obj;
699 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
700 android.Manifest.permission.WRITE_MEDIA_STORAGE);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800701 break;
702 }
703 case H_PARTITION_FORGET: {
704 final String partGuid = (String) msg.obj;
705 forgetPartition(partGuid);
706 break;
707 }
708 case H_RESET: {
709 resetIfReadyAndConnected();
710 break;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700711 }
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800712 }
713 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700714 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700715
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700716 private final Handler mHandler;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800717
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700718 private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
719 @Override
720 public void onReceive(Context context, Intent intent) {
721 final String action = intent.getAction();
722 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700723 Preconditions.checkArgument(userId >= 0);
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700724
725 try {
726 if (Intent.ACTION_USER_ADDED.equals(action)) {
727 final UserManager um = mContext.getSystemService(UserManager.class);
728 final int userSerialNumber = um.getUserSerialNumber(userId);
729 mConnector.execute("volume", "user_added", userId, userSerialNumber);
730 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700731 synchronized (mVolumes) {
732 final int size = mVolumes.size();
733 for (int i = 0; i < size; i++) {
734 final VolumeInfo vol = mVolumes.valueAt(i);
735 if (vol.mountUserId == userId) {
736 vol.mountUserId = UserHandle.USER_NULL;
737 mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
738 }
739 }
740 }
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700741 mConnector.execute("volume", "user_removed", userId);
742 }
743 } catch (NativeDaemonConnectorException e) {
744 Slog.w(TAG, "Failed to send user details to vold", e);
745 }
746 }
747 };
748
Jeff Sharkey56e62932015-03-21 20:41:00 -0700749 @Override
750 public void waitForAsecScan() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700751 waitForLatch(mAsecsScanned, "mAsecsScanned");
Kenny Root51a573c2012-05-17 13:30:28 -0700752 }
753
San Mehat207e5382010-02-04 20:46:54 -0800754 private void waitForReady() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700755 waitForLatch(mConnectedSignal, "mConnectedSignal");
Kenny Root51a573c2012-05-17 13:30:28 -0700756 }
757
Jeff Sharkey48877892015-03-18 11:27:19 -0700758 private void waitForLatch(CountDownLatch latch, String condition) {
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700759 try {
760 waitForLatch(latch, condition, -1);
761 } catch (TimeoutException ignored) {
762 }
763 }
764
765 private void waitForLatch(CountDownLatch latch, String condition, long timeoutMillis)
766 throws TimeoutException {
767 final long startMillis = SystemClock.elapsedRealtime();
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700768 while (true) {
Kenny Root51a573c2012-05-17 13:30:28 -0700769 try {
770 if (latch.await(5000, TimeUnit.MILLISECONDS)) {
San Mehat207e5382010-02-04 20:46:54 -0800771 return;
Kenny Root51a573c2012-05-17 13:30:28 -0700772 } else {
773 Slog.w(TAG, "Thread " + Thread.currentThread().getName()
Jeff Sharkey48877892015-03-18 11:27:19 -0700774 + " still waiting for " + condition + "...");
San Mehat207e5382010-02-04 20:46:54 -0800775 }
Kenny Root51a573c2012-05-17 13:30:28 -0700776 } catch (InterruptedException e) {
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700777 Slog.w(TAG, "Interrupt while waiting for " + condition);
San Mehat207e5382010-02-04 20:46:54 -0800778 }
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700779 if (timeoutMillis > 0 && SystemClock.elapsedRealtime() > startMillis + timeoutMillis) {
780 throw new TimeoutException("Thread " + Thread.currentThread().getName()
781 + " gave up waiting for " + condition + " after " + timeoutMillis + "ms");
782 }
San Mehat207e5382010-02-04 20:46:54 -0800783 }
San Mehat1f6301e2010-01-07 22:40:27 -0800784 }
Kenny Root02c87302010-07-01 08:10:18 -0700785
Paul Lawrence945490c2014-03-27 16:37:28 +0000786 private boolean isReady() {
787 try {
788 return mConnectedSignal.await(0, TimeUnit.MILLISECONDS);
789 } catch (InterruptedException e) {
790 return false;
791 }
792 }
793
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700794 private void handleSystemReady() {
Jeff Sharkey8924e872015-11-30 12:52:10 -0700795 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800796 resetIfReadyAndConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700797
Jeff Sharkey48877892015-03-18 11:27:19 -0700798 // Start scheduling nominally-daily fstrim operations
Christopher Tate115afda2014-06-06 19:06:26 -0700799 MountServiceIdler.scheduleIdlePass(mContext);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700800 }
801
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700802 /**
803 * MediaProvider has a ton of code that makes assumptions about storage
804 * paths never changing, so we outright kill them to pick up new state.
805 */
806 @Deprecated
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700807 private void killMediaProvider(List<UserInfo> users) {
808 if (users == null) return;
809
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700810 final long token = Binder.clearCallingIdentity();
811 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700812 for (UserInfo user : users) {
813 // System user does not have media provider, so skip.
814 if (user.isSystemOnly()) continue;
815
Jeff Sharkey2a9e3f82015-12-18 10:57:58 -0700816 final ProviderInfo provider = mPms.resolveContentProvider(MediaStore.AUTHORITY,
Jeff Sharkey8a372a02016-03-16 16:25:45 -0600817 PackageManager.MATCH_DIRECT_BOOT_AWARE
818 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
819 user.id);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700820 if (provider != null) {
821 final IActivityManager am = ActivityManagerNative.getDefault();
822 try {
823 am.killApplicationWithAppId(provider.applicationInfo.packageName,
824 UserHandle.getAppId(provider.applicationInfo.uid), "vold reset");
825 // We only need to run this once. It will kill all users' media processes.
826 break;
827 } catch (RemoteException e) {
828 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700829 }
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700830 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700831 } finally {
832 Binder.restoreCallingIdentity(token);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700833 }
834 }
835
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800836 private void addInternalVolumeLocked() {
Amith Yamasania7892482015-08-07 11:09:05 -0700837 // Create a stub volume that represents internal storage
838 final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
839 VolumeInfo.TYPE_PRIVATE, null, null);
840 internal.state = VolumeInfo.STATE_MOUNTED;
841 internal.path = Environment.getDataDirectory().getAbsolutePath();
842 mVolumes.put(internal.id, internal);
843 }
844
Jeff Sharkey8924e872015-11-30 12:52:10 -0700845 private void initIfReadyAndConnected() {
846 Slog.d(TAG, "Thinking about init, mSystemReady=" + mSystemReady
847 + ", mDaemonConnected=" + mDaemonConnected);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700848 if (mSystemReady && mDaemonConnected
Paul Lawrence20be5d62016-02-26 13:51:17 -0800849 && !StorageManager.isFileEncryptedNativeOnly()) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700850 // When booting a device without native support, make sure that our
851 // user directories are locked or unlocked based on the current
852 // emulation status.
Paul Lawrence20be5d62016-02-26 13:51:17 -0800853 final boolean initLocked = StorageManager.isFileEncryptedEmulatedOnly();
Paul Crowleyd94ab732016-02-15 06:44:51 +0000854 Slog.d(TAG, "Setting up emulation state, initlocked=" + initLocked);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700855 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Jeff Sharkey8924e872015-11-30 12:52:10 -0700856 for (UserInfo user : users) {
857 try {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700858 if (initLocked) {
859 mCryptConnector.execute("cryptfs", "lock_user_key", user.id);
860 } else {
861 mCryptConnector.execute("cryptfs", "unlock_user_key", user.id,
Paul Crowleyd94ab732016-02-15 06:44:51 +0000862 user.serialNumber, "!", "!");
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700863 }
Jeff Sharkey8924e872015-11-30 12:52:10 -0700864 } catch (NativeDaemonConnectorException e) {
865 Slog.w(TAG, "Failed to init vold", e);
866 }
867 }
868 }
869 }
870
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800871 private void resetIfReadyAndConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700872 Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
873 + ", mDaemonConnected=" + mDaemonConnected);
874 if (mSystemReady && mDaemonConnected) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800875 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700876 killMediaProvider(users);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700877
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700878 final int[] systemUnlockedUsers;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800879 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700880 systemUnlockedUsers = mSystemUnlockedUsers;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700881
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800882 mDisks.clear();
883 mVolumes.clear();
884
885 addInternalVolumeLocked();
886 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700887
Jeff Sharkey48877892015-03-18 11:27:19 -0700888 try {
889 mConnector.execute("volume", "reset");
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700890
891 // Tell vold about all existing and started users
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700892 for (UserInfo user : users) {
893 mConnector.execute("volume", "user_added", user.id, user.serialNumber);
894 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700895 for (int userId : systemUnlockedUsers) {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700896 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey50a05452015-04-29 11:24:52 -0700897 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700898 } catch (NativeDaemonConnectorException e) {
899 Slog.w(TAG, "Failed to reset vold", e);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700900 }
901 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700902 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700903
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700904 private void onUnlockUser(int userId) {
905 Slog.d(TAG, "onUnlockUser " + userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700906
907 // We purposefully block here to make sure that user-specific
908 // staging area is ready so it's ready for zygote-forked apps to
909 // bind mount against.
910 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700911 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700912 } catch (NativeDaemonConnectorException ignored) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700913 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700914
915 // Record user as started so newly mounted volumes kick off events
916 // correctly, then synthesize events for any already-mounted volumes.
917 synchronized (mVolumes) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700918 for (int i = 0; i < mVolumes.size(); i++) {
919 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey46349872015-07-28 10:49:47 -0700920 if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700921 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey48877892015-03-18 11:27:19 -0700922 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700923
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700924 final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
925 mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700926 }
927 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700928 mSystemUnlockedUsers = ArrayUtils.appendInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700929 }
930 }
931
932 private void onCleanupUser(int userId) {
933 Slog.d(TAG, "onCleanupUser " + userId);
934
935 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700936 mConnector.execute("volume", "user_stopped", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700937 } catch (NativeDaemonConnectorException ignored) {
938 }
939
940 synchronized (mVolumes) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700941 mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700942 }
943 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700944
Christopher Tated417d622013-08-19 16:14:25 -0700945 void runIdleMaintenance(Runnable callback) {
946 mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
947 }
948
Christopher Tate7265abe2014-11-21 13:54:45 -0800949 // Binder entry point for kicking off an immediate fstrim
950 @Override
951 public void runMaintenance() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700952 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Christopher Tate7265abe2014-11-21 13:54:45 -0800953 runIdleMaintenance(null);
954 }
955
956 @Override
957 public long lastMaintenance() {
958 return mLastMaintenance;
959 }
960
San Mehat4270e1e2010-01-29 05:32:19 -0800961 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800962 * Callback from NativeDaemonConnector
963 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700964 @Override
San Mehat4270e1e2010-01-29 05:32:19 -0800965 public void onDaemonConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700966 mDaemonConnected = true;
967 mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();
968 }
969
970 private void handleDaemonConnected() {
Jeff Sharkey8924e872015-11-30 12:52:10 -0700971 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800972 resetIfReadyAndConnected();
Jeff Sharkey48877892015-03-18 11:27:19 -0700973
San Mehat4270e1e2010-01-29 05:32:19 -0800974 /*
Jeff Sharkey48877892015-03-18 11:27:19 -0700975 * Now that we've done our initialization, release
976 * the hounds!
San Mehat4270e1e2010-01-29 05:32:19 -0800977 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700978 mConnectedSignal.countDown();
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700979 if (mConnectedSignal.getCount() != 0) {
980 // More daemons need to connect
981 return;
982 }
Mike Lockwood7fa24aa2011-03-23 14:52:34 -0400983
Jeff Sharkey48877892015-03-18 11:27:19 -0700984 // On an encrypted device we can't see system properties yet, so pull
985 // the system locale out of the mount service.
986 if ("".equals(SystemProperties.get("vold.encrypt_progress"))) {
987 copyLocaleFromMountService();
988 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700989
Jeff Sharkey48877892015-03-18 11:27:19 -0700990 // Let package manager load internal ASECs.
991 mPms.scanAvailableAsecs();
Mike Lockwood7fa24aa2011-03-23 14:52:34 -0400992
Jeff Sharkey48877892015-03-18 11:27:19 -0700993 // Notify people waiting for ASECs to be scanned that it's done.
994 mAsecsScanned.countDown();
San Mehat4270e1e2010-01-29 05:32:19 -0800995 }
996
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700997 private void copyLocaleFromMountService() {
998 String systemLocale;
999 try {
1000 systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
1001 } catch (RemoteException e) {
1002 return;
1003 }
1004 if (TextUtils.isEmpty(systemLocale)) {
1005 return;
1006 }
1007
1008 Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
1009 Locale locale = Locale.forLanguageTag(systemLocale);
1010 Configuration config = new Configuration();
1011 config.setLocale(locale);
1012 try {
Seigo Nonaka4963dfe2016-03-31 20:50:21 +09001013 ActivityManagerNative.getDefault().updatePersistentConfiguration(config);
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001014 } catch (RemoteException e) {
1015 Slog.e(TAG, "Error setting system locale from mount service", e);
1016 }
Elliott Hughes9c33f282014-10-13 12:39:56 -07001017
1018 // Temporary workaround for http://b/17945169.
1019 Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
Narayan Kamathd30dbb82015-01-15 14:48:15 +00001020 SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001021 }
1022
San Mehat4270e1e2010-01-29 05:32:19 -08001023 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001024 * Callback from NativeDaemonConnector
1025 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001026 @Override
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001027 public boolean onCheckHoldWakeLock(int code) {
1028 return false;
1029 }
1030
1031 /**
1032 * Callback from NativeDaemonConnector
1033 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001034 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001035 public boolean onEvent(int code, String raw, String[] cooked) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001036 synchronized (mLock) {
1037 return onEventLocked(code, raw, cooked);
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -08001038 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001039 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001040
Jeff Sharkey48877892015-03-18 11:27:19 -07001041 private boolean onEventLocked(int code, String raw, String[] cooked) {
1042 switch (code) {
1043 case VoldResponseCode.DISK_CREATED: {
1044 if (cooked.length != 3) break;
1045 final String id = cooked[1];
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001046 int flags = Integer.parseInt(cooked[2]);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001047 if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false)
1048 || mForceAdoptable) {
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001049 flags |= DiskInfo.FLAG_ADOPTABLE;
1050 }
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001051 mDisks.put(id, new DiskInfo(id, flags));
Jeff Sharkey48877892015-03-18 11:27:19 -07001052 break;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001053 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001054 case VoldResponseCode.DISK_SIZE_CHANGED: {
1055 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001056 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001057 if (disk != null) {
1058 disk.size = Long.parseLong(cooked[2]);
San Mehat4270e1e2010-01-29 05:32:19 -08001059 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001060 break;
1061 }
1062 case VoldResponseCode.DISK_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001063 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001064 if (disk != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001065 final StringBuilder builder = new StringBuilder();
1066 for (int i = 2; i < cooked.length; i++) {
1067 builder.append(cooked[i]).append(' ');
1068 }
1069 disk.label = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001070 }
1071 break;
1072 }
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001073 case VoldResponseCode.DISK_SCANNED: {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001074 if (cooked.length != 2) break;
1075 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001076 if (disk != null) {
1077 onDiskScannedLocked(disk);
1078 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -07001079 break;
1080 }
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001081 case VoldResponseCode.DISK_SYS_PATH_CHANGED: {
1082 if (cooked.length != 3) break;
1083 final DiskInfo disk = mDisks.get(cooked[1]);
1084 if (disk != null) {
1085 disk.sysPath = cooked[2];
1086 }
1087 break;
1088 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001089 case VoldResponseCode.DISK_DESTROYED: {
1090 if (cooked.length != 2) break;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07001091 final DiskInfo disk = mDisks.remove(cooked[1]);
1092 if (disk != null) {
1093 mCallbacks.notifyDiskDestroyed(disk);
1094 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001095 break;
1096 }
San Mehat4270e1e2010-01-29 05:32:19 -08001097
Jeff Sharkey48877892015-03-18 11:27:19 -07001098 case VoldResponseCode.VOLUME_CREATED: {
Jeff Sharkey48877892015-03-18 11:27:19 -07001099 final String id = cooked[1];
1100 final int type = Integer.parseInt(cooked[2]);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001101 final String diskId = TextUtils.nullIfEmpty(cooked[3]);
1102 final String partGuid = TextUtils.nullIfEmpty(cooked[4]);
1103
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001104 final DiskInfo disk = mDisks.get(diskId);
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07001105 final VolumeInfo vol = new VolumeInfo(id, type, disk, partGuid);
Jeff Sharkey48877892015-03-18 11:27:19 -07001106 mVolumes.put(id, vol);
1107 onVolumeCreatedLocked(vol);
1108 break;
1109 }
1110 case VoldResponseCode.VOLUME_STATE_CHANGED: {
1111 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001112 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001113 if (vol != null) {
1114 final int oldState = vol.state;
1115 final int newState = Integer.parseInt(cooked[2]);
1116 vol.state = newState;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001117 onVolumeStateChangedLocked(vol, oldState, newState);
Jeff Sharkey48877892015-03-18 11:27:19 -07001118 }
1119 break;
1120 }
1121 case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: {
1122 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001123 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001124 if (vol != null) {
1125 vol.fsType = cooked[2];
1126 }
1127 break;
1128 }
1129 case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
1130 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001131 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001132 if (vol != null) {
1133 vol.fsUuid = cooked[2];
1134 }
1135 break;
1136 }
1137 case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001138 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001139 if (vol != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001140 final StringBuilder builder = new StringBuilder();
1141 for (int i = 2; i < cooked.length; i++) {
1142 builder.append(cooked[i]).append(' ');
1143 }
1144 vol.fsLabel = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001145 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001146 // TODO: notify listeners that label changed
Jeff Sharkey48877892015-03-18 11:27:19 -07001147 break;
1148 }
1149 case VoldResponseCode.VOLUME_PATH_CHANGED: {
1150 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001151 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001152 if (vol != null) {
1153 vol.path = cooked[2];
1154 }
1155 break;
1156 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001157 case VoldResponseCode.VOLUME_INTERNAL_PATH_CHANGED: {
1158 if (cooked.length != 3) break;
1159 final VolumeInfo vol = mVolumes.get(cooked[1]);
1160 if (vol != null) {
1161 vol.internalPath = cooked[2];
1162 }
1163 break;
1164 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001165 case VoldResponseCode.VOLUME_DESTROYED: {
1166 if (cooked.length != 2) break;
1167 mVolumes.remove(cooked[1]);
1168 break;
1169 }
San Mehat4270e1e2010-01-29 05:32:19 -08001170
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001171 case VoldResponseCode.MOVE_STATUS: {
1172 final int status = Integer.parseInt(cooked[1]);
1173 onMoveStatusLocked(status);
1174 break;
1175 }
Jeff Sharkey9756d752015-05-14 21:07:42 -07001176 case VoldResponseCode.BENCHMARK_RESULT: {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001177 if (cooked.length != 7) break;
1178 final String path = cooked[1];
1179 final String ident = cooked[2];
1180 final long create = Long.parseLong(cooked[3]);
1181 final long drop = Long.parseLong(cooked[4]);
1182 final long run = Long.parseLong(cooked[5]);
1183 final long destroy = Long.parseLong(cooked[6]);
1184
Jeff Sharkey9756d752015-05-14 21:07:42 -07001185 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001186 dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
1187 + " " + ident + " " + create + " " + run + " " + destroy);
1188
1189 final VolumeRecord rec = findRecordForPath(path);
1190 if (rec != null) {
1191 rec.lastBenchMillis = System.currentTimeMillis();
1192 writeSettingsLocked();
1193 }
1194
1195 break;
1196 }
1197 case VoldResponseCode.TRIM_RESULT: {
1198 if (cooked.length != 4) break;
1199 final String path = cooked[1];
1200 final long bytes = Long.parseLong(cooked[2]);
1201 final long time = Long.parseLong(cooked[3]);
1202
1203 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
1204 dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path)
1205 + " " + bytes + " " + time);
1206
1207 final VolumeRecord rec = findRecordForPath(path);
1208 if (rec != null) {
1209 rec.lastTrimMillis = System.currentTimeMillis();
1210 writeSettingsLocked();
1211 }
1212
Jeff Sharkey9756d752015-05-14 21:07:42 -07001213 break;
1214 }
1215
Jeff Sharkey48877892015-03-18 11:27:19 -07001216 default: {
1217 Slog.d(TAG, "Unhandled vold event " + code);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001218 }
San Mehat4270e1e2010-01-29 05:32:19 -08001219 }
1220
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001221 return true;
San Mehat4270e1e2010-01-29 05:32:19 -08001222 }
1223
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001224 private void onDiskScannedLocked(DiskInfo disk) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001225 int volumeCount = 0;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001226 for (int i = 0; i < mVolumes.size(); i++) {
1227 final VolumeInfo vol = mVolumes.valueAt(i);
1228 if (Objects.equals(disk.id, vol.getDiskId())) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001229 volumeCount++;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001230 }
1231 }
1232
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001233 final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
Jeff Sharkey7732e1e2016-03-30 17:14:23 -06001234 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1235 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001236 intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
1237 intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001238 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001239
1240 final CountDownLatch latch = mDiskScanLatches.remove(disk.id);
1241 if (latch != null) {
1242 latch.countDown();
1243 }
1244
Jeff Sharkeyf5a6bd72015-05-19 14:42:38 -07001245 disk.volumeCount = volumeCount;
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001246 mCallbacks.notifyDiskScanned(disk, volumeCount);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001247 }
1248
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001249 private void onVolumeCreatedLocked(VolumeInfo vol) {
Jeff Sharkey6855c482016-03-31 14:34:38 -06001250 if (mPms.isOnlyCoreApps()) {
1251 Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId());
1252 return;
1253 }
1254
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001255 if (vol.type == VolumeInfo.TYPE_EMULATED) {
1256 final StorageManager storage = mContext.getSystemService(StorageManager.class);
1257 final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
1258
1259 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
1260 && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
1261 Slog.v(TAG, "Found primary storage at " + vol);
1262 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1263 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1264 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1265
1266 } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
1267 Slog.v(TAG, "Found primary storage at " + vol);
1268 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1269 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1270 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1271 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001272
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001273 } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001274 // TODO: only look at first public partition
1275 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1276 && vol.disk.isDefaultPrimary()) {
1277 Slog.v(TAG, "Found primary storage at " + vol);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001278 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1279 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
San Mehat4270e1e2010-01-29 05:32:19 -08001280 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001281
1282 // Adoptable public disks are visible to apps, since they meet
1283 // public API requirement of being in a stable location.
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001284 if (vol.disk.isAdoptable()) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001285 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1286 }
1287
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07001288 vol.mountUserId = ActivityManager.getCurrentUser();
Jeff Sharkey48877892015-03-18 11:27:19 -07001289 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001290
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001291 } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1292 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1293
San Mehat4270e1e2010-01-29 05:32:19 -08001294 } else {
Jeff Sharkey48877892015-03-18 11:27:19 -07001295 Slog.d(TAG, "Skipping automatic mounting of " + vol);
San Mehat4270e1e2010-01-29 05:32:19 -08001296 }
1297 }
1298
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001299 private boolean isBroadcastWorthy(VolumeInfo vol) {
1300 switch (vol.getType()) {
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001301 case VolumeInfo.TYPE_PRIVATE:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001302 case VolumeInfo.TYPE_PUBLIC:
1303 case VolumeInfo.TYPE_EMULATED:
1304 break;
1305 default:
1306 return false;
1307 }
1308
1309 switch (vol.getState()) {
1310 case VolumeInfo.STATE_MOUNTED:
1311 case VolumeInfo.STATE_MOUNTED_READ_ONLY:
1312 case VolumeInfo.STATE_EJECTING:
1313 case VolumeInfo.STATE_UNMOUNTED:
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001314 case VolumeInfo.STATE_UNMOUNTABLE:
Tony Mantlerf0d71052015-06-24 11:45:25 -07001315 case VolumeInfo.STATE_BAD_REMOVAL:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001316 break;
1317 default:
1318 return false;
1319 }
1320
1321 return true;
1322 }
1323
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001324 private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001325 // Remember that we saw this volume so we're ready to accept user
1326 // metadata, or so we can annoy them when a private volume is ejected
1327 if (vol.isMountedReadable() && !TextUtils.isEmpty(vol.fsUuid)) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001328 VolumeRecord rec = mRecords.get(vol.fsUuid);
1329 if (rec == null) {
1330 rec = new VolumeRecord(vol.type, vol.fsUuid);
1331 rec.partGuid = vol.partGuid;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001332 rec.createdMillis = System.currentTimeMillis();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001333 if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1334 rec.nickname = vol.disk.getDescription();
1335 }
1336 mRecords.put(rec.fsUuid, rec);
1337 writeSettingsLocked();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001338 } else {
1339 // Handle upgrade case where we didn't store partition GUID
1340 if (TextUtils.isEmpty(rec.partGuid)) {
1341 rec.partGuid = vol.partGuid;
1342 writeSettingsLocked();
1343 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001344 }
1345 }
1346
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001347 mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
1348
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001349 // Do not broadcast before boot has completed to avoid launching the
1350 // processes that receive the intent unnecessarily.
1351 if (mBootCompleted && isBroadcastWorthy(vol)) {
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001352 final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001353 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
1354 intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
Tony Mantlerf0d71052015-06-24 11:45:25 -07001355 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
Jeff Sharkey7732e1e2016-03-30 17:14:23 -06001356 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1357 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001358 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001359 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001360
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001361 final String oldStateEnv = VolumeInfo.getEnvironmentForState(oldState);
1362 final String newStateEnv = VolumeInfo.getEnvironmentForState(newState);
Emily Bernier92aa5a22014-07-07 10:11:48 -04001363
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001364 if (!Objects.equals(oldStateEnv, newStateEnv)) {
1365 // Kick state changed event towards all started users. Any users
1366 // started after this point will trigger additional
1367 // user-specific broadcasts.
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001368 for (int userId : mSystemUnlockedUsers) {
Jeff Sharkey46349872015-07-28 10:49:47 -07001369 if (vol.isVisibleForRead(userId)) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001370 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001371 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey48877892015-03-18 11:27:19 -07001372
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001373 mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
1374 newStateEnv);
San Mehat4270e1e2010-01-29 05:32:19 -08001375 }
1376 }
1377 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001378
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001379 if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.state == VolumeInfo.STATE_EJECTING) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001380 // TODO: this should eventually be handled by new ObbVolume state changes
1381 /*
1382 * Some OBBs might have been unmounted when this volume was
1383 * unmounted, so send a message to the handler to let it know to
1384 * remove those from the list of mounted OBBS.
1385 */
1386 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
1387 OBB_FLUSH_MOUNT_STATE, vol.path));
1388 }
San Mehat4270e1e2010-01-29 05:32:19 -08001389 }
1390
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001391 private void onMoveStatusLocked(int status) {
1392 if (mMoveCallback == null) {
1393 Slog.w(TAG, "Odd, status but no move requested");
1394 return;
1395 }
1396
1397 // TODO: estimate remaining time
1398 try {
Jeff Sharkey50a05452015-04-29 11:24:52 -07001399 mMoveCallback.onStatusChanged(-1, status, -1);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001400 } catch (RemoteException ignored) {
1401 }
1402
1403 // We've finished copying and we're about to clean up old data, so
1404 // remember that move was successful if we get rebooted
1405 if (status == MOVE_STATUS_COPY_FINISHED) {
1406 Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
1407
1408 mPrimaryStorageUuid = mMoveTargetUuid;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001409 writeSettingsLocked();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001410 }
1411
1412 if (PackageManager.isMoveStatusFinished(status)) {
1413 Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status);
1414
1415 mMoveCallback = null;
1416 mMoveTargetUuid = null;
1417 }
1418 }
1419
Jeff Sharkey48877892015-03-18 11:27:19 -07001420 private void enforcePermission(String perm) {
1421 mContext.enforceCallingOrSelfPermission(perm, perm);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001422 }
1423
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001424 /**
1425 * Decide if volume is mountable per device policies.
1426 */
1427 private boolean isMountDisallowed(VolumeInfo vol) {
1428 if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
1429 final UserManager userManager = mContext.getSystemService(UserManager.class);
1430 return userManager.hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
1431 Binder.getCallingUserHandle());
1432 } else {
1433 return false;
Emily Bernier92aa5a22014-07-07 10:11:48 -04001434 }
1435 }
1436
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001437 private void enforceAdminUser() {
1438 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1439 final int callingUserId = UserHandle.getCallingUserId();
1440 boolean isAdmin;
1441 long token = Binder.clearCallingIdentity();
1442 try {
1443 isAdmin = um.getUserInfo(callingUserId).isAdmin();
1444 } finally {
1445 Binder.restoreCallingIdentity(token);
1446 }
1447 if (!isAdmin) {
1448 throw new SecurityException("Only admin users can adopt sd cards");
1449 }
1450 }
1451
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001452 /**
San Mehat207e5382010-02-04 20:46:54 -08001453 * Constructs a new MountService instance
1454 *
1455 * @param context Binder context for this service
1456 */
1457 public MountService(Context context) {
Christopher Tated417d622013-08-19 16:14:25 -07001458 sSelf = this;
1459
San Mehat207e5382010-02-04 20:46:54 -08001460 mContext = context;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001461 mCallbacks = new Callbacks(FgThread.get().getLooper());
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001462 mLockPatternUtils = new LockPatternUtils(mContext);
San Mehat207e5382010-02-04 20:46:54 -08001463
San Mehat207e5382010-02-04 20:46:54 -08001464 // XXX: This will go away soon in favor of IMountServiceObserver
1465 mPms = (PackageManagerService) ServiceManager.getService("package");
1466
Dianne Hackbornefa92b22013-05-03 14:11:43 -07001467 HandlerThread hthread = new HandlerThread(TAG);
1468 hthread.start();
1469 mHandler = new MountServiceHandler(hthread.getLooper());
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001470
Kenny Roota02b8b02010-08-05 16:14:17 -07001471 // Add OBB Action Handler to MountService thread.
Dianne Hackborn8d044e82013-04-30 17:24:15 -07001472 mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
Kenny Roota02b8b02010-08-05 16:14:17 -07001473
Christopher Tate7265abe2014-11-21 13:54:45 -08001474 // Initialize the last-fstrim tracking if necessary
1475 File dataDir = Environment.getDataDirectory();
1476 File systemDir = new File(dataDir, "system");
1477 mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
1478 if (!mLastMaintenanceFile.exists()) {
1479 // Not setting mLastMaintenance here means that we will force an
1480 // fstrim during reboot following the OTA that installs this code.
1481 try {
1482 (new FileOutputStream(mLastMaintenanceFile)).close();
1483 } catch (IOException e) {
1484 Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
1485 }
1486 } else {
1487 mLastMaintenance = mLastMaintenanceFile.lastModified();
1488 }
1489
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001490 mSettingsFile = new AtomicFile(
Jeff Sharkey8212ae02016-02-10 14:46:43 -07001491 new File(Environment.getDataSystemDirectory(), "storage.xml"));
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001492
1493 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001494 readSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001495 }
1496
Svet Ganov6ee871e2015-07-10 14:29:33 -07001497 LocalServices.addService(MountServiceInternal.class, mMountServiceInternal);
1498
Marco Nelissenc34ebce2010-02-18 13:39:41 -08001499 /*
Kenny Root305bcbf2010-09-03 07:56:38 -07001500 * Create the connection to vold with a maximum queue of twice the
1501 * amount of containers we'd ever expect to have. This keeps an
1502 * "asec list" from blocking a thread repeatedly.
1503 */
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001504
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001505 mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
1506 null);
Jeff Sharkey48877892015-03-18 11:27:19 -07001507 mConnector.setDebug(true);
Jeff Sharkey8948c012015-11-03 12:33:54 -08001508 mConnector.setWarnIfHeld(mLock);
Jeff Sharkeycd575992016-03-29 14:12:49 -06001509 mConnectorThread = new Thread(mConnector, VOLD_TAG);
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07001510
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001511 // Reuse parameters from first connector since they are tested and safe
1512 mCryptConnector = new NativeDaemonConnector(this, "cryptd",
1513 MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
1514 mCryptConnector.setDebug(true);
Jeff Sharkeycd575992016-03-29 14:12:49 -06001515 mCryptConnectorThread = new Thread(mCryptConnector, CRYPTD_TAG);
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001516
Jeff Sharkeybcd262d2015-06-10 09:41:17 -07001517 final IntentFilter userFilter = new IntentFilter();
1518 userFilter.addAction(Intent.ACTION_USER_ADDED);
1519 userFilter.addAction(Intent.ACTION_USER_REMOVED);
1520 mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
1521
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001522 synchronized (mLock) {
1523 addInternalVolumeLocked();
1524 }
Amith Yamasania7892482015-08-07 11:09:05 -07001525
Kenny Root07714d42011-08-17 17:49:28 -07001526 // Add ourself to the Watchdog monitors if enabled.
1527 if (WATCHDOG_ENABLE) {
1528 Watchdog.getInstance().addMonitor(this);
1529 }
San Mehat207e5382010-02-04 20:46:54 -08001530 }
1531
Jeff Sharkeycd575992016-03-29 14:12:49 -06001532 private void start() {
1533 mConnectorThread.start();
1534 mCryptConnectorThread.start();
1535 }
1536
Jeff Sharkey56e62932015-03-21 20:41:00 -07001537 private void systemReady() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001538 mSystemReady = true;
1539 mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
1540 }
1541
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001542 private void bootCompleted() {
1543 mBootCompleted = true;
1544 }
1545
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001546 private String getDefaultPrimaryStorageUuid() {
1547 if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) {
1548 return StorageManager.UUID_PRIMARY_PHYSICAL;
1549 } else {
1550 return StorageManager.UUID_PRIVATE_INTERNAL;
1551 }
1552 }
1553
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001554 private void readSettingsLocked() {
1555 mRecords.clear();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001556 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001557 mForceAdoptable = false;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001558
1559 FileInputStream fis = null;
1560 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001561 fis = mSettingsFile.openRead();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001562 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001563 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001564
1565 int type;
1566 while ((type = in.next()) != END_DOCUMENT) {
1567 if (type == START_TAG) {
1568 final String tag = in.getName();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001569 if (TAG_VOLUMES.equals(tag)) {
1570 final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001571 final boolean primaryPhysical = SystemProperties.getBoolean(
1572 StorageManager.PROP_PRIMARY_PHYSICAL, false);
1573 final boolean validAttr = (version >= VERSION_FIX_PRIMARY)
1574 || (version >= VERSION_ADD_PRIMARY && !primaryPhysical);
1575 if (validAttr) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001576 mPrimaryStorageUuid = readStringAttribute(in,
1577 ATTR_PRIMARY_STORAGE_UUID);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001578 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001579 mForceAdoptable = readBooleanAttribute(in, ATTR_FORCE_ADOPTABLE, false);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001580
1581 } else if (TAG_VOLUME.equals(tag)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001582 final VolumeRecord rec = readVolumeRecord(in);
1583 mRecords.put(rec.fsUuid, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001584 }
1585 }
1586 }
1587 } catch (FileNotFoundException e) {
1588 // Missing metadata is okay, probably first boot
1589 } catch (IOException e) {
1590 Slog.wtf(TAG, "Failed reading metadata", e);
1591 } catch (XmlPullParserException e) {
1592 Slog.wtf(TAG, "Failed reading metadata", e);
1593 } finally {
1594 IoUtils.closeQuietly(fis);
1595 }
1596 }
1597
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001598 private void writeSettingsLocked() {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001599 FileOutputStream fos = null;
1600 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001601 fos = mSettingsFile.startWrite();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001602
1603 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001604 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001605 out.startDocument(null, true);
1606 out.startTag(null, TAG_VOLUMES);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001607 writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001608 writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001609 writeBooleanAttribute(out, ATTR_FORCE_ADOPTABLE, mForceAdoptable);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001610 final int size = mRecords.size();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001611 for (int i = 0; i < size; i++) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001612 final VolumeRecord rec = mRecords.valueAt(i);
1613 writeVolumeRecord(out, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001614 }
1615 out.endTag(null, TAG_VOLUMES);
1616 out.endDocument();
1617
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001618 mSettingsFile.finishWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001619 } catch (IOException e) {
1620 if (fos != null) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001621 mSettingsFile.failWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001622 }
1623 }
1624 }
1625
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001626 public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
1627 final int type = readIntAttribute(in, ATTR_TYPE);
1628 final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
1629 final VolumeRecord meta = new VolumeRecord(type, fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001630 meta.partGuid = readStringAttribute(in, ATTR_PART_GUID);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001631 meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
1632 meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001633 meta.createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
1634 meta.lastTrimMillis = readLongAttribute(in, ATTR_LAST_TRIM_MILLIS);
1635 meta.lastBenchMillis = readLongAttribute(in, ATTR_LAST_BENCH_MILLIS);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001636 return meta;
1637 }
1638
1639 public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
1640 out.startTag(null, TAG_VOLUME);
1641 writeIntAttribute(out, ATTR_TYPE, rec.type);
1642 writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001643 writeStringAttribute(out, ATTR_PART_GUID, rec.partGuid);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001644 writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
1645 writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001646 writeLongAttribute(out, ATTR_CREATED_MILLIS, rec.createdMillis);
1647 writeLongAttribute(out, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
1648 writeLongAttribute(out, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001649 out.endTag(null, TAG_VOLUME);
1650 }
1651
San Mehat207e5382010-02-04 20:46:54 -08001652 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001653 * Exposed API calls below here
1654 */
1655
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001656 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001657 public void registerListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001658 mCallbacks.register(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001659 }
1660
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001661 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001662 public void unregisterListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001663 mCallbacks.unregister(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001664 }
1665
Jeff Sharkey48877892015-03-18 11:27:19 -07001666 @Override
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -08001667 public void shutdown(final IMountShutdownObserver observer) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001668 enforcePermission(android.Manifest.permission.SHUTDOWN);
San Mehat4270e1e2010-01-29 05:32:19 -08001669
San Mehata5078592010-03-25 09:36:54 -07001670 Slog.i(TAG, "Shutting down");
Jeff Sharkey48877892015-03-18 11:27:19 -07001671 mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001672 }
1673
Jeff Sharkey48877892015-03-18 11:27:19 -07001674 @Override
San Mehatb1043402010-02-05 08:26:50 -08001675 public boolean isUsbMassStorageConnected() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001676 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001677 }
1678
Jeff Sharkey48877892015-03-18 11:27:19 -07001679 @Override
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -08001680 public void setUsbMassStorageEnabled(boolean enable) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001681 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001682 }
1683
Jeff Sharkey48877892015-03-18 11:27:19 -07001684 @Override
San Mehatb1043402010-02-05 08:26:50 -08001685 public boolean isUsbMassStorageEnabled() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001686 throw new UnsupportedOperationException();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001687 }
Jason parks9ed98bc2011-01-17 09:58:35 -06001688
Jeff Sharkey48877892015-03-18 11:27:19 -07001689 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001690 public String getVolumeState(String mountPoint) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001691 throw new UnsupportedOperationException();
San Mehat7fd0fee2009-12-17 07:12:23 -08001692 }
1693
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001694 @Override
Kenny Roote1ff2142010-10-12 11:20:01 -07001695 public boolean isExternalStorageEmulated() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001696 throw new UnsupportedOperationException();
Kenny Roote1ff2142010-10-12 11:20:01 -07001697 }
1698
Jeff Sharkey48877892015-03-18 11:27:19 -07001699 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001700 public int mountVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001701 mount(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001702 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001703 }
1704
Jeff Sharkey48877892015-03-18 11:27:19 -07001705 @Override
Ben Komalo13c71972011-09-07 16:35:56 -07001706 public void unmountVolume(String path, boolean force, boolean removeEncryption) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001707 unmount(findVolumeIdForPathOrThrow(path));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001708 }
1709
Jeff Sharkey48877892015-03-18 11:27:19 -07001710 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001711 public int formatVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001712 format(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001713 return 0;
1714 }
1715
1716 @Override
1717 public void mount(String volId) {
1718 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1719 waitForReady();
1720
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001721 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001722 if (isMountDisallowed(vol)) {
1723 throw new SecurityException("Mounting " + volId + " restricted by policy");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001724 }
1725 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001726 mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001727 } catch (NativeDaemonConnectorException e) {
1728 throw e.rethrowAsParcelableException();
1729 }
1730 }
1731
1732 @Override
1733 public void unmount(String volId) {
1734 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1735 waitForReady();
1736
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001737 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001738
1739 // TODO: expand PMS to know about multiple volumes
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001740 if (vol.isPrimaryPhysical()) {
1741 final long ident = Binder.clearCallingIdentity();
1742 try {
1743 synchronized (mUnmountLock) {
1744 mUnmountSignal = new CountDownLatch(1);
1745 mPms.updateExternalMediaStatus(false, true);
1746 waitForLatch(mUnmountSignal, "mUnmountSignal");
1747 mUnmountSignal = null;
1748 }
1749 } finally {
1750 Binder.restoreCallingIdentity(ident);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001751 }
1752 }
1753
1754 try {
1755 mConnector.execute("volume", "unmount", vol.id);
1756 } catch (NativeDaemonConnectorException e) {
1757 throw e.rethrowAsParcelableException();
1758 }
1759 }
1760
1761 @Override
1762 public void format(String volId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001763 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -08001764 waitForReady();
San Mehat5b77dab2010-01-26 13:28:50 -08001765
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001766 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001767 try {
Jeff Sharkey4e83cc92015-05-27 14:38:39 -07001768 mConnector.execute("volume", "format", vol.id, "auto");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001769 } catch (NativeDaemonConnectorException e) {
1770 throw e.rethrowAsParcelableException();
Jeff Sharkey48877892015-03-18 11:27:19 -07001771 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001772 }
1773
1774 @Override
Jeff Sharkey9756d752015-05-14 21:07:42 -07001775 public long benchmark(String volId) {
1776 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1777 waitForReady();
1778
1779 try {
Jeff Sharkey14cbe522015-07-08 14:06:37 -07001780 // TODO: make benchmark async so we don't block other commands
1781 final NativeDaemonEvent res = mConnector.execute(3 * DateUtils.MINUTE_IN_MILLIS,
1782 "volume", "benchmark", volId);
Jeff Sharkey9756d752015-05-14 21:07:42 -07001783 return Long.parseLong(res.getMessage());
Todd Kennedy8101ee62015-06-23 13:35:28 -07001784 } catch (NativeDaemonTimeoutException e) {
1785 return Long.MAX_VALUE;
Jeff Sharkey9756d752015-05-14 21:07:42 -07001786 } catch (NativeDaemonConnectorException e) {
1787 throw e.rethrowAsParcelableException();
1788 }
1789 }
1790
1791 @Override
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001792 public void partitionPublic(String diskId) {
1793 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1794 waitForReady();
1795
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001796 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001797 try {
1798 mConnector.execute("volume", "partition", diskId, "public");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001799 waitForLatch(latch, "partitionPublic", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001800 } catch (NativeDaemonConnectorException e) {
1801 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001802 } catch (TimeoutException e) {
1803 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001804 }
1805 }
1806
1807 @Override
1808 public void partitionPrivate(String diskId) {
1809 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001810 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001811 waitForReady();
1812
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001813 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001814 try {
1815 mConnector.execute("volume", "partition", diskId, "private");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001816 waitForLatch(latch, "partitionPrivate", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001817 } catch (NativeDaemonConnectorException e) {
1818 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001819 } catch (TimeoutException e) {
1820 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001821 }
1822 }
1823
1824 @Override
1825 public void partitionMixed(String diskId, int ratio) {
1826 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001827 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001828 waitForReady();
1829
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001830 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001831 try {
1832 mConnector.execute("volume", "partition", diskId, "mixed", ratio);
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001833 waitForLatch(latch, "partitionMixed", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001834 } catch (NativeDaemonConnectorException e) {
1835 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001836 } catch (TimeoutException e) {
1837 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001838 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001839 }
1840
Jeff Sharkey48877892015-03-18 11:27:19 -07001841 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001842 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001843 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1844 waitForReady();
1845
Jeff Sharkey50a05452015-04-29 11:24:52 -07001846 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001847 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001848 final VolumeRecord rec = mRecords.get(fsUuid);
1849 rec.nickname = nickname;
Jeff Sharkey50a05452015-04-29 11:24:52 -07001850 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001851 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001852 }
1853 }
1854
1855 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001856 public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001857 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1858 waitForReady();
1859
Jeff Sharkey50a05452015-04-29 11:24:52 -07001860 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001861 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001862 final VolumeRecord rec = mRecords.get(fsUuid);
1863 rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001864 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001865 writeSettingsLocked();
1866 }
1867 }
1868
1869 @Override
1870 public void forgetVolume(String fsUuid) {
1871 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1872 waitForReady();
1873
Jeff Sharkey50a05452015-04-29 11:24:52 -07001874 Preconditions.checkNotNull(fsUuid);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001875
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001876 synchronized (mLock) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001877 final VolumeRecord rec = mRecords.remove(fsUuid);
1878 if (rec != null && !TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001879 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001880 }
1881 mCallbacks.notifyVolumeForgotten(fsUuid);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001882
1883 // If this had been primary storage, revert back to internal and
1884 // reset vold so we bind into new volume into place.
1885 if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001886 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001887 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001888 }
1889
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001890 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001891 }
1892 }
1893
Jeff Sharkey7d2af542015-05-12 15:27:15 -07001894 @Override
1895 public void forgetAllVolumes() {
1896 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1897 waitForReady();
1898
Jeff Sharkey50a05452015-04-29 11:24:52 -07001899 synchronized (mLock) {
1900 for (int i = 0; i < mRecords.size(); i++) {
1901 final String fsUuid = mRecords.keyAt(i);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001902 final VolumeRecord rec = mRecords.valueAt(i);
1903 if (!TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001904 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001905 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001906 mCallbacks.notifyVolumeForgotten(fsUuid);
1907 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001908 mRecords.clear();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001909
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001910 if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)) {
1911 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
1912 }
1913
1914 writeSettingsLocked();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001915 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001916 }
1917 }
1918
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001919 private void forgetPartition(String partGuid) {
1920 try {
1921 mConnector.execute("volume", "forget_partition", partGuid);
1922 } catch (NativeDaemonConnectorException e) {
1923 Slog.w(TAG, "Failed to forget key for " + partGuid + ": " + e);
1924 }
1925 }
1926
Svet Ganov6ee871e2015-07-10 14:29:33 -07001927 private void remountUidExternalStorage(int uid, int mode) {
Jeff Sharkey9527b222015-06-24 15:24:48 -07001928 waitForReady();
1929
Svet Ganov6ee871e2015-07-10 14:29:33 -07001930 String modeName = "none";
1931 switch (mode) {
1932 case Zygote.MOUNT_EXTERNAL_DEFAULT: {
1933 modeName = "default";
1934 } break;
1935
1936 case Zygote.MOUNT_EXTERNAL_READ: {
1937 modeName = "read";
1938 } break;
1939
1940 case Zygote.MOUNT_EXTERNAL_WRITE: {
1941 modeName = "write";
1942 } break;
Jeff Sharkey9527b222015-06-24 15:24:48 -07001943 }
1944
1945 try {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001946 mConnector.execute("volume", "remount_uid", uid, modeName);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001947 } catch (NativeDaemonConnectorException e) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001948 Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001949 }
1950 }
1951
1952 @Override
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001953 public void setDebugFlags(int flags, int mask) {
1954 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1955 waitForReady();
1956
Jeff Sharkeyba512352015-11-12 20:17:45 -08001957 if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
Paul Lawrence20be5d62016-02-26 13:51:17 -08001958 if (StorageManager.isFileEncryptedNativeOnly()) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001959 throw new IllegalStateException(
1960 "Emulation not available on device with native FBE");
1961 }
Jeff Sharkey5a785162016-03-21 13:02:06 -06001962 if (mLockPatternUtils.isCredentialRequiredToDecrypt(false)) {
1963 throw new IllegalStateException(
1964 "Emulation requires disabling 'Secure start-up' in Settings > Security");
1965 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001966
Jeff Sharkey1176e512016-02-29 17:01:26 -07001967 final long token = Binder.clearCallingIdentity();
1968 try {
1969 final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
1970 SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001971
Jeff Sharkey1176e512016-02-29 17:01:26 -07001972 // Perform hard reboot to kick policy into place
1973 mContext.getSystemService(PowerManager.class).reboot(null);
1974 } finally {
1975 Binder.restoreCallingIdentity(token);
1976 }
Jeff Sharkeyba512352015-11-12 20:17:45 -08001977 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001978
Jeff Sharkeyba512352015-11-12 20:17:45 -08001979 if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
1980 synchronized (mLock) {
1981 mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
1982
1983 writeSettingsLocked();
1984 mHandler.obtainMessage(H_RESET).sendToTarget();
1985 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001986 }
Jeff Sharkey33dd1562016-04-07 11:05:33 -06001987
1988 if ((mask & (StorageManager.DEBUG_SDCARDFS_FORCE_ON
1989 | StorageManager.DEBUG_SDCARDFS_FORCE_OFF)) != 0) {
1990 final String value;
1991 if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_ON) != 0) {
1992 value = "force_on";
1993 } else if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_OFF) != 0) {
1994 value = "force_off";
1995 } else {
1996 value = "";
1997 }
1998
1999 final long token = Binder.clearCallingIdentity();
2000 try {
2001 SystemProperties.set(StorageManager.PROP_SDCARDFS, value);
2002
2003 // Reset storage to kick new setting into place
2004 mHandler.obtainMessage(H_RESET).sendToTarget();
2005 } finally {
2006 Binder.restoreCallingIdentity(token);
2007 }
2008 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002009 }
2010
2011 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002012 public String getPrimaryStorageUuid() {
2013 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2014 waitForReady();
2015
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002016 synchronized (mLock) {
2017 return mPrimaryStorageUuid;
2018 }
2019 }
2020
2021 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002022 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
2023 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2024 waitForReady();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002025
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002026 synchronized (mLock) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002027 if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) {
2028 throw new IllegalArgumentException("Primary storage already at " + volumeUuid);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002029 }
2030
2031 if (mMoveCallback != null) {
2032 throw new IllegalStateException("Move already in progress");
2033 }
2034 mMoveCallback = callback;
2035 mMoveTargetUuid = volumeUuid;
2036
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002037 // When moving to/from primary physical volume, we probably just nuked
2038 // the current storage location, so we have nothing to move.
2039 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
2040 || Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
2041 Slog.d(TAG, "Skipping move to/from primary physical");
2042 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
2043 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08002044 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002045
2046 } else {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07002047 final VolumeInfo from = findStorageForUuid(mPrimaryStorageUuid);
2048 final VolumeInfo to = findStorageForUuid(volumeUuid);
2049
2050 if (from == null) {
2051 Slog.w(TAG, "Failing move due to missing from volume " + mPrimaryStorageUuid);
2052 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2053 return;
2054 } else if (to == null) {
2055 Slog.w(TAG, "Failing move due to missing to volume " + volumeUuid);
2056 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2057 return;
2058 }
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002059
2060 try {
2061 mConnector.execute("volume", "move_storage", from.id, to.id);
2062 } catch (NativeDaemonConnectorException e) {
2063 throw e.rethrowAsParcelableException();
2064 }
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002065 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002066 }
2067 }
2068
2069 @Override
Mike Lockwoodecedfdc2011-06-08 15:11:59 -07002070 public int[] getStorageUsers(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002071 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehatc1b4ce92010-02-16 17:13:03 -08002072 waitForReady();
2073 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002074 final String[] r = NativeDaemonEvent.filterMessageList(
2075 mConnector.executeForList("storage", "users", path),
2076 VoldResponseCode.StorageUsersListResult);
2077
San Mehatc1b4ce92010-02-16 17:13:03 -08002078 // FMT: <pid> <process name>
2079 int[] data = new int[r.length];
2080 for (int i = 0; i < r.length; i++) {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002081 String[] tok = r[i].split(" ");
San Mehatc1b4ce92010-02-16 17:13:03 -08002082 try {
2083 data[i] = Integer.parseInt(tok[0]);
2084 } catch (NumberFormatException nfe) {
San Mehata5078592010-03-25 09:36:54 -07002085 Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
San Mehatc1b4ce92010-02-16 17:13:03 -08002086 return new int[0];
2087 }
2088 }
2089 return data;
2090 } catch (NativeDaemonConnectorException e) {
San Mehata5078592010-03-25 09:36:54 -07002091 Slog.e(TAG, "Failed to retrieve storage users list", e);
San Mehatc1b4ce92010-02-16 17:13:03 -08002092 return new int[0];
2093 }
2094 }
2095
San Mehatb1043402010-02-05 08:26:50 -08002096 private void warnOnNotMounted() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002097 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002098 for (int i = 0; i < mVolumes.size(); i++) {
2099 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07002100 if (vol.isPrimary() && vol.isMountedWritable()) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002101 // Cool beans, we have a mounted primary volume
2102 return;
2103 }
Jeff Sharkey32ee8312012-09-30 13:21:31 -07002104 }
San Mehatb1043402010-02-05 08:26:50 -08002105 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002106
2107 Slog.w(TAG, "No primary storage mounted!");
San Mehatb1043402010-02-05 08:26:50 -08002108 }
2109
San Mehat4270e1e2010-01-29 05:32:19 -08002110 public String[] getSecureContainerList() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002111 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002112 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002113 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002114
San Mehat4270e1e2010-01-29 05:32:19 -08002115 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002116 return NativeDaemonEvent.filterMessageList(
2117 mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
San Mehat4270e1e2010-01-29 05:32:19 -08002118 } catch (NativeDaemonConnectorException e) {
2119 return new String[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002120 }
2121 }
San Mehat36972292010-01-06 11:06:32 -08002122
Kenny Root6dceb882012-04-12 14:23:49 -07002123 public int createSecureContainer(String id, int sizeMb, String fstype, String key,
2124 int ownerUid, boolean external) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002125 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehat207e5382010-02-04 20:46:54 -08002126 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002127 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002128
San Mehatb1043402010-02-05 08:26:50 -08002129 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002130 try {
Jeff Sharkey56cd6462013-06-07 15:09:15 -07002131 mConnector.execute("asec", "create", id, sizeMb, fstype, new SensitiveArg(key),
2132 ownerUid, external ? "1" : "0");
San Mehat4270e1e2010-01-29 05:32:19 -08002133 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002134 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002135 }
San Mehata181b212010-02-11 06:50:20 -08002136
2137 if (rc == StorageResultCode.OperationSucceeded) {
2138 synchronized (mAsecMountSet) {
2139 mAsecMountSet.add(id);
2140 }
2141 }
San Mehat4270e1e2010-01-29 05:32:19 -08002142 return rc;
San Mehat36972292010-01-06 11:06:32 -08002143 }
2144
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002145 @Override
2146 public int resizeSecureContainer(String id, int sizeMb, String key) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002147 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002148 waitForReady();
2149 warnOnNotMounted();
2150
2151 int rc = StorageResultCode.OperationSucceeded;
2152 try {
2153 mConnector.execute("asec", "resize", id, sizeMb, new SensitiveArg(key));
2154 } catch (NativeDaemonConnectorException e) {
2155 rc = StorageResultCode.OperationFailedInternalError;
2156 }
2157 return rc;
2158 }
2159
San Mehat4270e1e2010-01-29 05:32:19 -08002160 public int finalizeSecureContainer(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002161 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehatb1043402010-02-05 08:26:50 -08002162 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002163
San Mehatb1043402010-02-05 08:26:50 -08002164 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002165 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002166 mConnector.execute("asec", "finalize", id);
San Mehata181b212010-02-11 06:50:20 -08002167 /*
2168 * Finalization does a remount, so no need
2169 * to update mAsecMountSet
2170 */
San Mehat4270e1e2010-01-29 05:32:19 -08002171 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002172 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002173 }
San Mehat4270e1e2010-01-29 05:32:19 -08002174 return rc;
San Mehat36972292010-01-06 11:06:32 -08002175 }
2176
Kenny Root6dceb882012-04-12 14:23:49 -07002177 public int fixPermissionsSecureContainer(String id, int gid, String filename) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002178 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Kenny Root6dceb882012-04-12 14:23:49 -07002179 warnOnNotMounted();
2180
2181 int rc = StorageResultCode.OperationSucceeded;
2182 try {
2183 mConnector.execute("asec", "fixperms", id, gid, filename);
2184 /*
2185 * Fix permissions does a remount, so no need to update
2186 * mAsecMountSet
2187 */
2188 } catch (NativeDaemonConnectorException e) {
2189 rc = StorageResultCode.OperationFailedInternalError;
2190 }
2191 return rc;
2192 }
2193
San Mehatd9709982010-02-18 11:43:03 -08002194 public int destroySecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002195 enforcePermission(android.Manifest.permission.ASEC_DESTROY);
San Mehat207e5382010-02-04 20:46:54 -08002196 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002197 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002198
Kenny Rootaa485402010-09-14 14:49:41 -07002199 /*
2200 * Force a GC to make sure AssetManagers in other threads of the
2201 * system_server are cleaned up. We have to do this since AssetManager
2202 * instances are kept as a WeakReference and it's possible we have files
2203 * open on the external storage.
2204 */
2205 Runtime.getRuntime().gc();
2206
San Mehatb1043402010-02-05 08:26:50 -08002207 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002208 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002209 final Command cmd = new Command("asec", "destroy", id);
2210 if (force) {
2211 cmd.appendArg("force");
2212 }
2213 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002214 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002215 int code = e.getCode();
2216 if (code == VoldResponseCode.OpFailedStorageBusy) {
2217 rc = StorageResultCode.OperationFailedStorageBusy;
2218 } else {
2219 rc = StorageResultCode.OperationFailedInternalError;
2220 }
San Mehat02735bc2010-01-26 15:18:08 -08002221 }
San Mehata181b212010-02-11 06:50:20 -08002222
2223 if (rc == StorageResultCode.OperationSucceeded) {
2224 synchronized (mAsecMountSet) {
2225 if (mAsecMountSet.contains(id)) {
2226 mAsecMountSet.remove(id);
2227 }
2228 }
2229 }
2230
San Mehat4270e1e2010-01-29 05:32:19 -08002231 return rc;
San Mehat36972292010-01-06 11:06:32 -08002232 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002233
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002234 public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002235 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002236 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002237 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002238
San Mehata181b212010-02-11 06:50:20 -08002239 synchronized (mAsecMountSet) {
2240 if (mAsecMountSet.contains(id)) {
2241 return StorageResultCode.OperationFailedStorageMounted;
2242 }
2243 }
2244
San Mehatb1043402010-02-05 08:26:50 -08002245 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002246 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002247 mConnector.execute("asec", "mount", id, new SensitiveArg(key), ownerUid,
2248 readOnly ? "ro" : "rw");
San Mehat4270e1e2010-01-29 05:32:19 -08002249 } catch (NativeDaemonConnectorException e) {
Kenny Rootf0304622010-03-19 19:20:42 -07002250 int code = e.getCode();
2251 if (code != VoldResponseCode.OpFailedStorageBusy) {
2252 rc = StorageResultCode.OperationFailedInternalError;
2253 }
San Mehat02735bc2010-01-26 15:18:08 -08002254 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002255
2256 if (rc == StorageResultCode.OperationSucceeded) {
2257 synchronized (mAsecMountSet) {
2258 mAsecMountSet.add(id);
2259 }
2260 }
San Mehat4270e1e2010-01-29 05:32:19 -08002261 return rc;
San Mehat36972292010-01-06 11:06:32 -08002262 }
2263
San Mehatd9709982010-02-18 11:43:03 -08002264 public int unmountSecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002265 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002266 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002267 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002268
San Mehat6cdd9c02010-02-09 14:45:20 -08002269 synchronized (mAsecMountSet) {
2270 if (!mAsecMountSet.contains(id)) {
San Mehata181b212010-02-11 06:50:20 -08002271 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehat6cdd9c02010-02-09 14:45:20 -08002272 }
2273 }
2274
Kenny Rootaa485402010-09-14 14:49:41 -07002275 /*
2276 * Force a GC to make sure AssetManagers in other threads of the
2277 * system_server are cleaned up. We have to do this since AssetManager
2278 * instances are kept as a WeakReference and it's possible we have files
2279 * open on the external storage.
2280 */
2281 Runtime.getRuntime().gc();
2282
San Mehatb1043402010-02-05 08:26:50 -08002283 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002284 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002285 final Command cmd = new Command("asec", "unmount", id);
2286 if (force) {
2287 cmd.appendArg("force");
2288 }
2289 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002290 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002291 int code = e.getCode();
2292 if (code == VoldResponseCode.OpFailedStorageBusy) {
2293 rc = StorageResultCode.OperationFailedStorageBusy;
2294 } else {
2295 rc = StorageResultCode.OperationFailedInternalError;
2296 }
San Mehat02735bc2010-01-26 15:18:08 -08002297 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002298
2299 if (rc == StorageResultCode.OperationSucceeded) {
2300 synchronized (mAsecMountSet) {
2301 mAsecMountSet.remove(id);
2302 }
2303 }
San Mehat4270e1e2010-01-29 05:32:19 -08002304 return rc;
San Mehat9dba7092010-01-18 06:47:41 -08002305 }
2306
San Mehat6cdd9c02010-02-09 14:45:20 -08002307 public boolean isSecureContainerMounted(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002308 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat6cdd9c02010-02-09 14:45:20 -08002309 waitForReady();
2310 warnOnNotMounted();
2311
2312 synchronized (mAsecMountSet) {
2313 return mAsecMountSet.contains(id);
2314 }
2315 }
2316
San Mehat4270e1e2010-01-29 05:32:19 -08002317 public int renameSecureContainer(String oldId, String newId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002318 enforcePermission(android.Manifest.permission.ASEC_RENAME);
San Mehat207e5382010-02-04 20:46:54 -08002319 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002320 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002321
San Mehata181b212010-02-11 06:50:20 -08002322 synchronized (mAsecMountSet) {
San Mehat85451ee2010-02-24 08:54:18 -08002323 /*
Jason parks9ed98bc2011-01-17 09:58:35 -06002324 * Because a mounted container has active internal state which cannot be
San Mehat85451ee2010-02-24 08:54:18 -08002325 * changed while active, we must ensure both ids are not currently mounted.
2326 */
2327 if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
San Mehata181b212010-02-11 06:50:20 -08002328 return StorageResultCode.OperationFailedStorageMounted;
2329 }
2330 }
2331
San Mehatb1043402010-02-05 08:26:50 -08002332 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002333 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002334 mConnector.execute("asec", "rename", oldId, newId);
San Mehat4270e1e2010-01-29 05:32:19 -08002335 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002336 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002337 }
San Mehata181b212010-02-11 06:50:20 -08002338
San Mehat4270e1e2010-01-29 05:32:19 -08002339 return rc;
San Mehat45f61042010-01-23 08:12:43 -08002340 }
2341
San Mehat4270e1e2010-01-29 05:32:19 -08002342 public String getSecureContainerPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002343 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002344 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002345 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002346
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002347 final NativeDaemonEvent event;
San Mehat2d66cef2010-03-23 11:12:52 -07002348 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002349 event = mConnector.execute("asec", "path", id);
2350 event.checkCode(VoldResponseCode.AsecPathResult);
2351 return event.getMessage();
San Mehat2d66cef2010-03-23 11:12:52 -07002352 } catch (NativeDaemonConnectorException e) {
2353 int code = e.getCode();
2354 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Fredrik Helmera20c8ef2011-02-09 16:16:10 +01002355 Slog.i(TAG, String.format("Container '%s' not found", id));
2356 return null;
San Mehat22dd86e2010-01-12 12:21:18 -08002357 } else {
San Mehat2d66cef2010-03-23 11:12:52 -07002358 throw new IllegalStateException(String.format("Unexpected response code %d", code));
San Mehat22dd86e2010-01-12 12:21:18 -08002359 }
2360 }
San Mehat22dd86e2010-01-12 12:21:18 -08002361 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002362
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002363 public String getSecureContainerFilesystemPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002364 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002365 waitForReady();
2366 warnOnNotMounted();
2367
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002368 final NativeDaemonEvent event;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002369 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002370 event = mConnector.execute("asec", "fspath", id);
2371 event.checkCode(VoldResponseCode.AsecPathResult);
2372 return event.getMessage();
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002373 } catch (NativeDaemonConnectorException e) {
2374 int code = e.getCode();
2375 if (code == VoldResponseCode.OpFailedStorageNotFound) {
2376 Slog.i(TAG, String.format("Container '%s' not found", id));
2377 return null;
2378 } else {
2379 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2380 }
2381 }
2382 }
2383
Jeff Sharkey48877892015-03-18 11:27:19 -07002384 @Override
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002385 public void finishMediaUpdate() {
Jeff Sharkey9527b222015-06-24 15:24:48 -07002386 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
Rubin Xucd7a0142015-04-17 23:45:27 +01002387 throw new SecurityException("no permission to call finishMediaUpdate()");
2388 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002389 if (mUnmountSignal != null) {
2390 mUnmountSignal.countDown();
2391 } else {
2392 Slog.w(TAG, "Odd, nobody asked to unmount?");
2393 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002394 }
Kenny Root02c87302010-07-01 08:10:18 -07002395
Kenny Roota02b8b02010-08-05 16:14:17 -07002396 private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
2397 if (callerUid == android.os.Process.SYSTEM_UID) {
2398 return true;
2399 }
2400
Kenny Root02c87302010-07-01 08:10:18 -07002401 if (packageName == null) {
2402 return false;
2403 }
2404
Jeff Sharkeycd654482016-01-08 17:42:11 -07002405 final int packageUid = mPms.getPackageUid(packageName,
2406 PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callerUid));
Kenny Root02c87302010-07-01 08:10:18 -07002407
2408 if (DEBUG_OBB) {
2409 Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
2410 packageUid + ", callerUid = " + callerUid);
2411 }
2412
2413 return callerUid == packageUid;
2414 }
2415
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002416 public String getMountedObbPath(String rawPath) {
2417 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002418
Kenny Root02c87302010-07-01 08:10:18 -07002419 waitForReady();
2420 warnOnNotMounted();
2421
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002422 final ObbState state;
Rubin Xucd7a0142015-04-17 23:45:27 +01002423 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002424 state = mObbPathToStateMap.get(rawPath);
2425 }
2426 if (state == null) {
2427 Slog.w(TAG, "Failed to find OBB mounted at " + rawPath);
2428 return null;
2429 }
2430
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002431 final NativeDaemonEvent event;
Kenny Root02c87302010-07-01 08:10:18 -07002432 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07002433 event = mConnector.execute("obb", "path", state.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002434 event.checkCode(VoldResponseCode.AsecPathResult);
2435 return event.getMessage();
Kenny Root02c87302010-07-01 08:10:18 -07002436 } catch (NativeDaemonConnectorException e) {
2437 int code = e.getCode();
2438 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Kenny Roota02b8b02010-08-05 16:14:17 -07002439 return null;
Kenny Root02c87302010-07-01 08:10:18 -07002440 } else {
2441 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2442 }
2443 }
2444 }
2445
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002446 @Override
2447 public boolean isObbMounted(String rawPath) {
2448 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002449 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002450 return mObbPathToStateMap.containsKey(rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002451 }
Kenny Root02c87302010-07-01 08:10:18 -07002452 }
2453
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002454 @Override
2455 public void mountObb(
2456 String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) {
2457 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2458 Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
2459 Preconditions.checkNotNull(token, "token cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002460
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002461 final int callingUid = Binder.getCallingUid();
2462 final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce);
2463 final ObbAction action = new MountObbAction(obbState, key, callingUid);
Kenny Roota02b8b02010-08-05 16:14:17 -07002464 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
2465
2466 if (DEBUG_OBB)
2467 Slog.i(TAG, "Send to OBB handler: " + action.toString());
Kenny Root02c87302010-07-01 08:10:18 -07002468 }
2469
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002470 @Override
2471 public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
2472 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2473
2474 final ObbState existingState;
Rubin Xucd7a0142015-04-17 23:45:27 +01002475 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002476 existingState = mObbPathToStateMap.get(rawPath);
Kenny Rootf1121dc2010-09-29 07:30:53 -07002477 }
2478
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002479 if (existingState != null) {
2480 // TODO: separate state object from request data
2481 final int callingUid = Binder.getCallingUid();
2482 final ObbState newState = new ObbState(
2483 rawPath, existingState.canonicalPath, callingUid, token, nonce);
2484 final ObbAction action = new UnmountObbAction(newState, force);
2485 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root02c87302010-07-01 08:10:18 -07002486
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002487 if (DEBUG_OBB)
2488 Slog.i(TAG, "Send to OBB handler: " + action.toString());
2489 } else {
2490 Slog.w(TAG, "Unknown OBB mount at " + rawPath);
2491 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002492 }
2493
Ben Komalo444eca22011-09-01 15:17:44 -07002494 @Override
2495 public int getEncryptionState() {
2496 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2497 "no permission to access the crypt keeper");
2498
2499 waitForReady();
2500
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002501 final NativeDaemonEvent event;
Ben Komalo444eca22011-09-01 15:17:44 -07002502 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002503 event = mCryptConnector.execute("cryptfs", "cryptocomplete");
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002504 return Integer.parseInt(event.getMessage());
Ben Komalo444eca22011-09-01 15:17:44 -07002505 } catch (NumberFormatException e) {
2506 // Bad result - unexpected.
2507 Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
2508 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2509 } catch (NativeDaemonConnectorException e) {
2510 // Something bad happened.
2511 Slog.w(TAG, "Error in communicating with cryptfs in validating");
2512 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2513 }
2514 }
2515
2516 @Override
Jason parks5af0b912010-11-29 09:05:25 -06002517 public int decryptStorage(String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002518 if (TextUtils.isEmpty(password)) {
2519 throw new IllegalArgumentException("password cannot be empty");
Jason parks5af0b912010-11-29 09:05:25 -06002520 }
2521
Jason parks8888c592011-01-20 22:46:41 -06002522 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2523 "no permission to access the crypt keeper");
Jason parks5af0b912010-11-29 09:05:25 -06002524
2525 waitForReady();
2526
2527 if (DEBUG_EVENTS) {
2528 Slog.i(TAG, "decrypting storage...");
2529 }
2530
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002531 final NativeDaemonEvent event;
Jason parks5af0b912010-11-29 09:05:25 -06002532 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002533 event = mCryptConnector.execute("cryptfs", "checkpw", new SensitiveArg(password));
Jason parks9ed98bc2011-01-17 09:58:35 -06002534
Fredrik Roubertda6aedf2011-12-20 17:34:43 +01002535 final int code = Integer.parseInt(event.getMessage());
Jason parks9ed98bc2011-01-17 09:58:35 -06002536 if (code == 0) {
2537 // Decrypt was successful. Post a delayed message before restarting in order
2538 // to let the UI to clear itself
2539 mHandler.postDelayed(new Runnable() {
2540 public void run() {
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002541 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002542 mCryptConnector.execute("cryptfs", "restart");
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002543 } catch (NativeDaemonConnectorException e) {
2544 Slog.e(TAG, "problem executing in background", e);
2545 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002546 }
Jason parksf7b3cd42011-01-27 09:28:25 -06002547 }, 1000); // 1 second
Jason parks9ed98bc2011-01-17 09:58:35 -06002548 }
2549
2550 return code;
Jason parks5af0b912010-11-29 09:05:25 -06002551 } catch (NativeDaemonConnectorException e) {
2552 // Decryption failed
2553 return e.getCode();
2554 }
Jason parks5af0b912010-11-29 09:05:25 -06002555 }
2556
Paul Lawrence46791e72014-04-03 09:10:26 -07002557 public int encryptStorage(int type, String password) {
2558 if (TextUtils.isEmpty(password) && type != StorageManager.CRYPT_TYPE_DEFAULT) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002559 throw new IllegalArgumentException("password cannot be empty");
Jason parks56aa5322011-01-07 09:01:15 -06002560 }
2561
Jason parks8888c592011-01-20 22:46:41 -06002562 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2563 "no permission to access the crypt keeper");
Jason parks56aa5322011-01-07 09:01:15 -06002564
2565 waitForReady();
2566
2567 if (DEBUG_EVENTS) {
Jason parks8888c592011-01-20 22:46:41 -06002568 Slog.i(TAG, "encrypting storage...");
Jason parks56aa5322011-01-07 09:01:15 -06002569 }
2570
2571 try {
Paul Lawrence5096d9e2015-09-09 13:05:45 -07002572 if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
2573 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2574 CRYPTO_TYPES[type]);
2575 } else {
2576 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2577 CRYPTO_TYPES[type], new SensitiveArg(password));
2578 }
Jason parks56aa5322011-01-07 09:01:15 -06002579 } catch (NativeDaemonConnectorException e) {
2580 // Encryption failed
2581 return e.getCode();
2582 }
2583
2584 return 0;
2585 }
2586
Paul Lawrence8e397362014-01-27 15:22:30 -08002587 /** Set the password for encrypting the master key.
2588 * @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
2589 * @param password The password to set.
2590 */
2591 public int changeEncryptionPassword(int type, String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002592 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2593 "no permission to access the crypt keeper");
2594
2595 waitForReady();
2596
2597 if (DEBUG_EVENTS) {
2598 Slog.i(TAG, "changing encryption password...");
2599 }
2600
2601 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002602 NativeDaemonEvent event = mCryptConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type],
Paul Lawrence05487612015-06-09 13:35:38 -07002603 new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002604 return Integer.parseInt(event.getMessage());
Jason parksf7b3cd42011-01-27 09:28:25 -06002605 } catch (NativeDaemonConnectorException e) {
2606 // Encryption failed
2607 return e.getCode();
2608 }
2609 }
2610
Christopher Tate32418be2011-10-10 13:51:12 -07002611 /**
2612 * Validate a user-supplied password string with cryptfs
2613 */
2614 @Override
2615 public int verifyEncryptionPassword(String password) throws RemoteException {
2616 // Only the system process is permitted to validate passwords
2617 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2618 throw new SecurityException("no permission to access the crypt keeper");
2619 }
2620
2621 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2622 "no permission to access the crypt keeper");
2623
2624 if (TextUtils.isEmpty(password)) {
2625 throw new IllegalArgumentException("password cannot be empty");
2626 }
2627
2628 waitForReady();
2629
2630 if (DEBUG_EVENTS) {
2631 Slog.i(TAG, "validating encryption password...");
2632 }
2633
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002634 final NativeDaemonEvent event;
Christopher Tate32418be2011-10-10 13:51:12 -07002635 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002636 event = mCryptConnector.execute("cryptfs", "verifypw", new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002637 Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
2638 return Integer.parseInt(event.getMessage());
Christopher Tate32418be2011-10-10 13:51:12 -07002639 } catch (NativeDaemonConnectorException e) {
2640 // Encryption failed
2641 return e.getCode();
2642 }
2643 }
2644
Paul Lawrence8e397362014-01-27 15:22:30 -08002645 /**
2646 * Get the type of encryption used to encrypt the master key.
2647 * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
2648 */
2649 @Override
Svetoslav16e4a1a2014-09-29 18:16:20 -07002650 public int getPasswordType() {
Paul Lawrence8e397362014-01-27 15:22:30 -08002651
2652 waitForReady();
2653
2654 final NativeDaemonEvent event;
2655 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002656 event = mCryptConnector.execute("cryptfs", "getpwtype");
Paul Lawrence8e397362014-01-27 15:22:30 -08002657 for (int i = 0; i < CRYPTO_TYPES.length; ++i) {
2658 if (CRYPTO_TYPES[i].equals(event.getMessage()))
2659 return i;
2660 }
2661
2662 throw new IllegalStateException("unexpected return from cryptfs");
2663 } catch (NativeDaemonConnectorException e) {
2664 throw e.rethrowAsParcelableException();
2665 }
2666 }
2667
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002668 /**
2669 * Set a field in the crypto header.
2670 * @param field field to set
2671 * @param contents contents to set in field
2672 */
2673 @Override
2674 public void setField(String field, String contents) throws RemoteException {
2675
2676 waitForReady();
2677
2678 final NativeDaemonEvent event;
2679 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002680 event = mCryptConnector.execute("cryptfs", "setfield", field, contents);
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002681 } catch (NativeDaemonConnectorException e) {
2682 throw e.rethrowAsParcelableException();
2683 }
2684 }
2685
2686 /**
2687 * Gets a field from the crypto header.
2688 * @param field field to get
2689 * @return contents of field
2690 */
2691 @Override
2692 public String getField(String field) throws RemoteException {
2693
2694 waitForReady();
2695
2696 final NativeDaemonEvent event;
2697 try {
2698 final String[] contents = NativeDaemonEvent.filterMessageList(
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002699 mCryptConnector.executeForList("cryptfs", "getfield", field),
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002700 VoldResponseCode.CryptfsGetfieldResult);
2701 String result = new String();
2702 for (String content : contents) {
2703 result += content;
2704 }
2705 return result;
2706 } catch (NativeDaemonConnectorException e) {
2707 throw e.rethrowAsParcelableException();
2708 }
2709 }
2710
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002711 /**
2712 * Is userdata convertible to file based encryption?
2713 * @return non zero for convertible
2714 */
2715 @Override
2716 public boolean isConvertibleToFBE() throws RemoteException {
2717
2718 waitForReady();
2719
2720 final NativeDaemonEvent event;
2721 try {
2722 event = mCryptConnector.execute("cryptfs", "isConvertibleToFBE");
2723 return Integer.parseInt(event.getMessage()) != 0;
2724 } catch (NativeDaemonConnectorException e) {
2725 throw e.rethrowAsParcelableException();
2726 }
2727 }
2728
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002729 @Override
Paul Lawrence945490c2014-03-27 16:37:28 +00002730 public String getPassword() throws RemoteException {
Rubin Xucd7a0142015-04-17 23:45:27 +01002731 mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE,
2732 "only keyguard can retrieve password");
Paul Lawrence945490c2014-03-27 16:37:28 +00002733 if (!isReady()) {
2734 return new String();
2735 }
2736
2737 final NativeDaemonEvent event;
2738 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002739 event = mCryptConnector.execute("cryptfs", "getpw");
Paul Lawrence24063b52015-01-06 13:11:23 -08002740 if ("-1".equals(event.getMessage())) {
2741 // -1 equals no password
2742 return null;
2743 }
Paul Lawrence05487612015-06-09 13:35:38 -07002744 return event.getMessage();
Paul Lawrence945490c2014-03-27 16:37:28 +00002745 } catch (NativeDaemonConnectorException e) {
2746 throw e.rethrowAsParcelableException();
Paul Lawrence24063b52015-01-06 13:11:23 -08002747 } catch (IllegalArgumentException e) {
2748 Slog.e(TAG, "Invalid response to getPassword");
2749 return null;
Paul Lawrence945490c2014-03-27 16:37:28 +00002750 }
2751 }
2752
2753 @Override
2754 public void clearPassword() throws RemoteException {
2755 if (!isReady()) {
2756 return;
2757 }
2758
2759 final NativeDaemonEvent event;
2760 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002761 event = mCryptConnector.execute("cryptfs", "clearpw");
Paul Lawrence945490c2014-03-27 16:37:28 +00002762 } catch (NativeDaemonConnectorException e) {
2763 throw e.rethrowAsParcelableException();
2764 }
2765 }
2766
2767 @Override
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002768 public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002769 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002770 waitForReady();
2771
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002772 try {
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002773 mCryptConnector.execute("cryptfs", "create_user_key", userId, serialNumber,
2774 ephemeral ? 1 : 0);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002775 } catch (NativeDaemonConnectorException e) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002776 throw e.rethrowAsParcelableException();
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002777 }
2778 }
2779
Paul Crowley7ec733f2015-05-19 12:42:00 +01002780 @Override
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002781 public void destroyUserKey(int userId) {
2782 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowley7ec733f2015-05-19 12:42:00 +01002783 waitForReady();
2784
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002785 try {
2786 mCryptConnector.execute("cryptfs", "destroy_user_key", userId);
2787 } catch (NativeDaemonConnectorException e) {
2788 throw e.rethrowAsParcelableException();
2789 }
2790 }
2791
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002792 private SensitiveArg encodeBytes(byte[] bytes) {
2793 if (ArrayUtils.isEmpty(bytes)) {
2794 return new SensitiveArg("!");
2795 } else {
2796 return new SensitiveArg(HexDump.toHexString(bytes));
2797 }
2798 }
2799
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002800 @Override
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002801 public void changeUserKey(int userId, int serialNumber,
2802 byte[] token, byte[] oldSecret, byte[] newSecret) {
2803 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2804 waitForReady();
2805
2806 try {
2807 mCryptConnector.execute("cryptfs", "change_user_key", userId, serialNumber,
2808 encodeBytes(token), encodeBytes(oldSecret), encodeBytes(newSecret));
2809 } catch (NativeDaemonConnectorException e) {
2810 throw e.rethrowAsParcelableException();
2811 }
2812 }
2813
2814 @Override
2815 public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002816 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2817 waitForReady();
2818
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07002819 // When a user has secure lock screen, require a challenge token to
2820 // actually unlock. This check is mostly in place for emulation mode.
2821 if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(token)) {
2822 throw new IllegalStateException("Token required to unlock secure user " + userId);
2823 }
2824
Paul Crowley7ec733f2015-05-19 12:42:00 +01002825 try {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002826 mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber,
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002827 encodeBytes(token), encodeBytes(secret));
Paul Crowley7ec733f2015-05-19 12:42:00 +01002828 } catch (NativeDaemonConnectorException e) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002829 throw e.rethrowAsParcelableException();
2830 }
2831
2832 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002833 mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002834 }
2835 }
2836
2837 @Override
2838 public void lockUserKey(int userId) {
2839 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2840 waitForReady();
2841
2842 try {
2843 mCryptConnector.execute("cryptfs", "lock_user_key", userId);
2844 } catch (NativeDaemonConnectorException e) {
2845 throw e.rethrowAsParcelableException();
2846 }
2847
2848 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002849 mLocalUnlockedUsers = ArrayUtils.removeInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002850 }
2851 }
2852
2853 @Override
2854 public boolean isUserKeyUnlocked(int userId) {
Paul Lawrence20be5d62016-02-26 13:51:17 -08002855 if (StorageManager.isFileEncryptedNativeOrEmulated()) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002856 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002857 return ArrayUtils.contains(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002858 }
2859 } else {
2860 return true;
2861 }
2862 }
2863
2864 @Override
Jeff Sharkey47f71082016-02-01 17:03:54 -07002865 public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002866 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2867 waitForReady();
2868
2869 try {
2870 mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid),
Jeff Sharkey47f71082016-02-01 17:03:54 -07002871 userId, serialNumber, flags);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002872 } catch (NativeDaemonConnectorException e) {
2873 throw e.rethrowAsParcelableException();
Paul Crowley7ec733f2015-05-19 12:42:00 +01002874 }
2875 }
2876
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002877 @Override
Jeff Sharkeyfcf1e552016-04-14 20:44:58 -06002878 public void destroyUserStorage(String volumeUuid, int userId, int flags) {
2879 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2880 waitForReady();
2881
2882 try {
2883 mCryptConnector.execute("cryptfs", "destroy_user_storage", escapeNull(volumeUuid),
2884 userId, flags);
2885 } catch (NativeDaemonConnectorException e) {
2886 throw e.rethrowAsParcelableException();
2887 }
2888 }
2889
2890 @Override
Daichi Hirono91e3b502015-12-16 09:24:16 +09002891 public ParcelFileDescriptor mountAppFuse(final String name) throws RemoteException {
Daichi Hironobee50c02015-12-14 11:00:54 +09002892 try {
Daichi Hirono91e3b502015-12-16 09:24:16 +09002893 final int uid = Binder.getCallingUid();
Daichi Hironofd7d57e2016-01-29 14:30:58 +09002894 final int pid = Binder.getCallingPid();
Daichi Hironobee50c02015-12-14 11:00:54 +09002895 final NativeDaemonEvent event =
Daichi Hironofd7d57e2016-01-29 14:30:58 +09002896 mConnector.execute("appfuse", "mount", uid, pid, name);
Daichi Hironobee50c02015-12-14 11:00:54 +09002897 if (event.getFileDescriptors() == null) {
Daichi Hirono91e3b502015-12-16 09:24:16 +09002898 throw new RemoteException("AppFuse FD from vold is null.");
Daichi Hironobee50c02015-12-14 11:00:54 +09002899 }
Daichi Hirono91e3b502015-12-16 09:24:16 +09002900 return ParcelFileDescriptor.fromFd(
2901 event.getFileDescriptors()[0],
2902 mHandler,
2903 new ParcelFileDescriptor.OnCloseListener() {
2904 @Override
2905 public void onClose(IOException e) {
2906 try {
2907 final NativeDaemonEvent event = mConnector.execute(
Daichi Hironofd7d57e2016-01-29 14:30:58 +09002908 "appfuse", "unmount", uid, pid, name);
Daichi Hirono91e3b502015-12-16 09:24:16 +09002909 } catch (NativeDaemonConnectorException unmountException) {
2910 Log.e(TAG, "Failed to unmount appfuse.");
2911 }
2912 }
2913 });
Daichi Hironobee50c02015-12-14 11:00:54 +09002914 } catch (NativeDaemonConnectorException e) {
2915 throw e.rethrowAsParcelableException();
Daichi Hirono91e3b502015-12-16 09:24:16 +09002916 } catch (IOException e) {
2917 throw new RemoteException(e.getMessage());
Daichi Hironobee50c02015-12-14 11:00:54 +09002918 }
Daichi Hirono9e8d9e22015-11-13 14:37:00 +09002919 }
2920
2921 @Override
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002922 public int mkdirs(String callingPkg, String appPath) {
2923 final int userId = UserHandle.getUserId(Binder.getCallingUid());
2924 final UserEnvironment userEnv = new UserEnvironment(userId);
2925
2926 // Validate that reported package name belongs to caller
2927 final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
2928 Context.APP_OPS_SERVICE);
2929 appOps.checkPackage(Binder.getCallingUid(), callingPkg);
2930
Jeff Sharkey48877892015-03-18 11:27:19 -07002931 File appFile = null;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002932 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07002933 appFile = new File(appPath).getCanonicalFile();
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002934 } catch (IOException e) {
2935 Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
2936 return -1;
2937 }
2938
2939 // Try translating the app path into a vold path, but require that it
2940 // belong to the calling package.
Jeff Sharkey48877892015-03-18 11:27:19 -07002941 if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) ||
2942 FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) ||
2943 FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) {
2944 appPath = appFile.getAbsolutePath();
2945 if (!appPath.endsWith("/")) {
2946 appPath = appPath + "/";
2947 }
2948
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002949 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07002950 mConnector.execute("volume", "mkdirs", appPath);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002951 return 0;
2952 } catch (NativeDaemonConnectorException e) {
2953 return e.getCode();
2954 }
2955 }
2956
Jeff Sharkey48877892015-03-18 11:27:19 -07002957 throw new SecurityException("Invalid mkdirs path: " + appFile);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002958 }
2959
2960 @Override
Jeff Sharkey46349872015-07-28 10:49:47 -07002961 public StorageVolume[] getVolumeList(int uid, String packageName, int flags) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002962 final int userId = UserHandle.getUserId(uid);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06002963
Jeff Sharkey46349872015-07-28 10:49:47 -07002964 final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0;
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06002965 final boolean realState = (flags & StorageManager.FLAG_REAL_STATE) != 0;
2966 final boolean includeInvisible = (flags & StorageManager.FLAG_INCLUDE_INVISIBLE) != 0;
Jeff Sharkey46349872015-07-28 10:49:47 -07002967
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06002968 final boolean userKeyUnlocked;
2969 final boolean storagePermission;
2970 final long token = Binder.clearCallingIdentity();
Svetoslav38c3dbb2015-07-14 11:27:06 -07002971 try {
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06002972 userKeyUnlocked = isUserKeyUnlocked(userId);
2973 storagePermission = mMountServiceInternal.hasExternalStorage(uid, packageName);
Svetoslav38c3dbb2015-07-14 11:27:06 -07002974 } finally {
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06002975 Binder.restoreCallingIdentity(token);
Svetoslav38c3dbb2015-07-14 11:27:06 -07002976 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07002977
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06002978 boolean foundPrimary = false;
2979
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002980 final ArrayList<StorageVolume> res = new ArrayList<>();
Jeff Sharkey48877892015-03-18 11:27:19 -07002981 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002982 for (int i = 0; i < mVolumes.size(); i++) {
2983 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06002984 switch (vol.getType()) {
2985 case VolumeInfo.TYPE_PUBLIC:
2986 case VolumeInfo.TYPE_EMULATED:
2987 break;
2988 default:
2989 continue;
2990 }
2991
2992 boolean match = false;
2993 if (forWrite) {
2994 match = vol.isVisibleForWrite(userId);
2995 } else {
2996 match = vol.isVisibleForRead(userId) || includeInvisible;
2997 }
2998 if (!match) continue;
2999
3000 boolean reportUnmounted = false;
3001 if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !userKeyUnlocked) {
3002 reportUnmounted = true;
3003 } else if (!storagePermission && !realState) {
3004 reportUnmounted = true;
3005 }
3006
3007 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
3008 reportUnmounted);
3009 if (vol.isPrimary()) {
3010 res.add(0, userVol);
3011 foundPrimary = true;
3012 } else {
3013 res.add(userVol);
Jeff Sharkeyb049e212012-09-07 23:16:01 -07003014 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003015 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003016 }
Jeff Sharkey48877892015-03-18 11:27:19 -07003017
3018 if (!foundPrimary) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003019 Log.w(TAG, "No primary storage defined yet; hacking together a stub");
Jeff Sharkey48877892015-03-18 11:27:19 -07003020
3021 final boolean primaryPhysical = SystemProperties.getBoolean(
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003022 StorageManager.PROP_PRIMARY_PHYSICAL, false);
Jeff Sharkey48877892015-03-18 11:27:19 -07003023
3024 final String id = "stub_primary";
3025 final File path = Environment.getLegacyExternalStorageDirectory();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003026 final String description = mContext.getString(android.R.string.unknownName);
Jeff Sharkey48877892015-03-18 11:27:19 -07003027 final boolean primary = true;
3028 final boolean removable = primaryPhysical;
3029 final boolean emulated = !primaryPhysical;
3030 final long mtpReserveSize = 0L;
3031 final boolean allowMassStorage = false;
3032 final long maxFileSize = 0L;
3033 final UserHandle owner = new UserHandle(userId);
3034 final String uuid = null;
Jeff Sharkey48877892015-03-18 11:27:19 -07003035 final String state = Environment.MEDIA_REMOVED;
3036
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07003037 res.add(0, new StorageVolume(id, StorageVolume.STORAGE_ID_INVALID, path,
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003038 description, primary, removable, emulated, mtpReserveSize,
3039 allowMassStorage, maxFileSize, owner, uuid, state));
Jeff Sharkey48877892015-03-18 11:27:19 -07003040 }
3041
3042 return res.toArray(new StorageVolume[res.size()]);
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003043 }
3044
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003045 @Override
3046 public DiskInfo[] getDisks() {
3047 synchronized (mLock) {
3048 final DiskInfo[] res = new DiskInfo[mDisks.size()];
3049 for (int i = 0; i < mDisks.size(); i++) {
3050 res[i] = mDisks.valueAt(i);
3051 }
3052 return res;
3053 }
3054 }
3055
3056 @Override
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003057 public VolumeInfo[] getVolumes(int flags) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003058 synchronized (mLock) {
3059 final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
3060 for (int i = 0; i < mVolumes.size(); i++) {
3061 res[i] = mVolumes.valueAt(i);
3062 }
3063 return res;
3064 }
3065 }
3066
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003067 @Override
3068 public VolumeRecord[] getVolumeRecords(int flags) {
3069 synchronized (mLock) {
3070 final VolumeRecord[] res = new VolumeRecord[mRecords.size()];
3071 for (int i = 0; i < mRecords.size(); i++) {
3072 res[i] = mRecords.valueAt(i);
3073 }
3074 return res;
3075 }
3076 }
3077
Kenny Rootaf9d6672010-10-08 09:21:39 -07003078 private void addObbStateLocked(ObbState obbState) throws RemoteException {
3079 final IBinder binder = obbState.getBinder();
3080 List<ObbState> obbStates = mObbMounts.get(binder);
Kenny Root5919ac62010-10-05 09:49:40 -07003081
Kenny Rootaf9d6672010-10-08 09:21:39 -07003082 if (obbStates == null) {
3083 obbStates = new ArrayList<ObbState>();
3084 mObbMounts.put(binder, obbStates);
3085 } else {
3086 for (final ObbState o : obbStates) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003087 if (o.rawPath.equals(obbState.rawPath)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003088 throw new IllegalStateException("Attempt to add ObbState twice. "
3089 + "This indicates an error in the MountService logic.");
Kenny Root5919ac62010-10-05 09:49:40 -07003090 }
3091 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003092 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003093
3094 obbStates.add(obbState);
3095 try {
3096 obbState.link();
3097 } catch (RemoteException e) {
3098 /*
3099 * The binder died before we could link it, so clean up our state
3100 * and return failure.
3101 */
3102 obbStates.remove(obbState);
3103 if (obbStates.isEmpty()) {
3104 mObbMounts.remove(binder);
3105 }
3106
3107 // Rethrow the error so mountObb can get it
3108 throw e;
3109 }
3110
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003111 mObbPathToStateMap.put(obbState.rawPath, obbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003112 }
3113
Kenny Rootaf9d6672010-10-08 09:21:39 -07003114 private void removeObbStateLocked(ObbState obbState) {
3115 final IBinder binder = obbState.getBinder();
3116 final List<ObbState> obbStates = mObbMounts.get(binder);
3117 if (obbStates != null) {
3118 if (obbStates.remove(obbState)) {
3119 obbState.unlink();
Kenny Root05105f72010-09-22 17:29:43 -07003120 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003121 if (obbStates.isEmpty()) {
3122 mObbMounts.remove(binder);
3123 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003124 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003125
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003126 mObbPathToStateMap.remove(obbState.rawPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003127 }
3128
Kenny Roota02b8b02010-08-05 16:14:17 -07003129 private class ObbActionHandler extends Handler {
3130 private boolean mBound = false;
Kenny Root480afe72010-10-07 10:17:50 -07003131 private final List<ObbAction> mActions = new LinkedList<ObbAction>();
Kenny Roota02b8b02010-08-05 16:14:17 -07003132
3133 ObbActionHandler(Looper l) {
3134 super(l);
3135 }
3136
3137 @Override
3138 public void handleMessage(Message msg) {
3139 switch (msg.what) {
3140 case OBB_RUN_ACTION: {
Kenny Root480afe72010-10-07 10:17:50 -07003141 final ObbAction action = (ObbAction) msg.obj;
Kenny Roota02b8b02010-08-05 16:14:17 -07003142
3143 if (DEBUG_OBB)
3144 Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
3145
3146 // If a bind was already initiated we don't really
3147 // need to do anything. The pending install
3148 // will be processed later on.
3149 if (!mBound) {
3150 // If this is the only one pending we might
3151 // have to bind to the service again.
3152 if (!connectToService()) {
3153 Slog.e(TAG, "Failed to bind to media container service");
3154 action.handleError();
3155 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003156 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003157 }
Kenny Root735de3b2010-09-30 14:11:39 -07003158
Kenny Root735de3b2010-09-30 14:11:39 -07003159 mActions.add(action);
Kenny Roota02b8b02010-08-05 16:14:17 -07003160 break;
3161 }
3162 case OBB_MCS_BOUND: {
3163 if (DEBUG_OBB)
3164 Slog.i(TAG, "OBB_MCS_BOUND");
3165 if (msg.obj != null) {
3166 mContainerService = (IMediaContainerService) msg.obj;
3167 }
3168 if (mContainerService == null) {
3169 // Something seriously wrong. Bail out
3170 Slog.e(TAG, "Cannot bind to media container service");
3171 for (ObbAction action : mActions) {
3172 // Indicate service bind error
3173 action.handleError();
3174 }
3175 mActions.clear();
3176 } else if (mActions.size() > 0) {
Kenny Root480afe72010-10-07 10:17:50 -07003177 final ObbAction action = mActions.get(0);
Kenny Roota02b8b02010-08-05 16:14:17 -07003178 if (action != null) {
3179 action.execute(this);
3180 }
3181 } else {
3182 // Should never happen ideally.
3183 Slog.w(TAG, "Empty queue");
3184 }
3185 break;
3186 }
3187 case OBB_MCS_RECONNECT: {
3188 if (DEBUG_OBB)
3189 Slog.i(TAG, "OBB_MCS_RECONNECT");
3190 if (mActions.size() > 0) {
3191 if (mBound) {
3192 disconnectService();
3193 }
3194 if (!connectToService()) {
3195 Slog.e(TAG, "Failed to bind to media container service");
3196 for (ObbAction action : mActions) {
3197 // Indicate service bind error
3198 action.handleError();
3199 }
3200 mActions.clear();
3201 }
3202 }
3203 break;
3204 }
3205 case OBB_MCS_UNBIND: {
3206 if (DEBUG_OBB)
3207 Slog.i(TAG, "OBB_MCS_UNBIND");
3208
3209 // Delete pending install
3210 if (mActions.size() > 0) {
3211 mActions.remove(0);
3212 }
3213 if (mActions.size() == 0) {
3214 if (mBound) {
3215 disconnectService();
3216 }
3217 } else {
3218 // There are more pending requests in queue.
3219 // Just post MCS_BOUND message to trigger processing
3220 // of next pending install.
3221 mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
3222 }
3223 break;
3224 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003225 case OBB_FLUSH_MOUNT_STATE: {
3226 final String path = (String) msg.obj;
3227
3228 if (DEBUG_OBB)
3229 Slog.i(TAG, "Flushing all OBB state for path " + path);
3230
3231 synchronized (mObbMounts) {
3232 final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
3233
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003234 final Iterator<ObbState> i = mObbPathToStateMap.values().iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003235 while (i.hasNext()) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003236 final ObbState state = i.next();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003237
3238 /*
3239 * If this entry's source file is in the volume path
3240 * that got unmounted, remove it because it's no
3241 * longer valid.
3242 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003243 if (state.canonicalPath.startsWith(path)) {
3244 obbStatesToRemove.add(state);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003245 }
3246 }
3247
3248 for (final ObbState obbState : obbStatesToRemove) {
3249 if (DEBUG_OBB)
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003250 Slog.i(TAG, "Removing state for " + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003251
3252 removeObbStateLocked(obbState);
3253
3254 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003255 obbState.token.onObbResult(obbState.rawPath, obbState.nonce,
Kenny Rootaf9d6672010-10-08 09:21:39 -07003256 OnObbStateChangeListener.UNMOUNTED);
3257 } catch (RemoteException e) {
3258 Slog.i(TAG, "Couldn't send unmount notification for OBB: "
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003259 + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003260 }
3261 }
3262 }
3263 break;
3264 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003265 }
3266 }
3267
3268 private boolean connectToService() {
3269 if (DEBUG_OBB)
3270 Slog.i(TAG, "Trying to bind to DefaultContainerService");
3271
3272 Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Jeff Sharkey6dce4962015-07-03 18:08:41 -07003273 if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE,
Xiaohui Chene4de5a02015-09-22 15:33:31 -07003274 UserHandle.SYSTEM)) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003275 mBound = true;
3276 return true;
3277 }
3278 return false;
3279 }
3280
3281 private void disconnectService() {
3282 mContainerService = null;
3283 mBound = false;
3284 mContext.unbindService(mDefContainerConn);
3285 }
3286 }
3287
3288 abstract class ObbAction {
3289 private static final int MAX_RETRIES = 3;
3290 private int mRetries;
3291
3292 ObbState mObbState;
3293
3294 ObbAction(ObbState obbState) {
3295 mObbState = obbState;
3296 }
3297
3298 public void execute(ObbActionHandler handler) {
3299 try {
3300 if (DEBUG_OBB)
Ben Komalo444eca22011-09-01 15:17:44 -07003301 Slog.i(TAG, "Starting to execute action: " + toString());
Kenny Roota02b8b02010-08-05 16:14:17 -07003302 mRetries++;
3303 if (mRetries > MAX_RETRIES) {
3304 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
Kenny Root480afe72010-10-07 10:17:50 -07003305 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003306 handleError();
Kenny Roota02b8b02010-08-05 16:14:17 -07003307 } else {
3308 handleExecute();
3309 if (DEBUG_OBB)
3310 Slog.i(TAG, "Posting install MCS_UNBIND");
3311 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
3312 }
3313 } catch (RemoteException e) {
3314 if (DEBUG_OBB)
3315 Slog.i(TAG, "Posting install MCS_RECONNECT");
3316 mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
3317 } catch (Exception e) {
3318 if (DEBUG_OBB)
3319 Slog.d(TAG, "Error handling OBB action", e);
3320 handleError();
Kenny Root17eb6fb2010-10-06 15:02:52 -07003321 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003322 }
3323 }
3324
Kenny Root05105f72010-09-22 17:29:43 -07003325 abstract void handleExecute() throws RemoteException, IOException;
Kenny Roota02b8b02010-08-05 16:14:17 -07003326 abstract void handleError();
Kenny Root38cf8862010-09-26 14:18:51 -07003327
3328 protected ObbInfo getObbInfo() throws IOException {
3329 ObbInfo obbInfo;
3330 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003331 obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003332 } catch (RemoteException e) {
3333 Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003334 + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003335 obbInfo = null;
3336 }
3337 if (obbInfo == null) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003338 throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003339 }
3340 return obbInfo;
3341 }
3342
Kenny Rootaf9d6672010-10-08 09:21:39 -07003343 protected void sendNewStatusOrIgnore(int status) {
3344 if (mObbState == null || mObbState.token == null) {
3345 return;
3346 }
3347
Kenny Root38cf8862010-09-26 14:18:51 -07003348 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003349 mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
Kenny Root38cf8862010-09-26 14:18:51 -07003350 } catch (RemoteException e) {
3351 Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
3352 }
3353 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003354 }
3355
3356 class MountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003357 private final String mKey;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003358 private final int mCallingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003359
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003360 MountObbAction(ObbState obbState, String key, int callingUid) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003361 super(obbState);
3362 mKey = key;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003363 mCallingUid = callingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003364 }
3365
Jason parks5af0b912010-11-29 09:05:25 -06003366 @Override
Kenny Root735de3b2010-09-30 14:11:39 -07003367 public void handleExecute() throws IOException, RemoteException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003368 waitForReady();
3369 warnOnNotMounted();
3370
Kenny Root38cf8862010-09-26 14:18:51 -07003371 final ObbInfo obbInfo = getObbInfo();
3372
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003373 if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003374 Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
3375 + " which is owned by " + obbInfo.packageName);
3376 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3377 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003378 }
3379
Kenny Rootaf9d6672010-10-08 09:21:39 -07003380 final boolean isMounted;
3381 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003382 isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003383 }
3384 if (isMounted) {
3385 Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
3386 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
3387 return;
3388 }
3389
Kenny Rootaf9d6672010-10-08 09:21:39 -07003390 final String hashedKey;
3391 if (mKey == null) {
3392 hashedKey = "none";
3393 } else {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003394 try {
Kenny Root3b1abba2010-10-13 15:00:07 -07003395 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
3396
3397 KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
3398 PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
3399 SecretKey key = factory.generateSecret(ks);
3400 BigInteger bi = new BigInteger(key.getEncoded());
3401 hashedKey = bi.toString(16);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003402 } catch (NoSuchAlgorithmException e) {
Kenny Root3b1abba2010-10-13 15:00:07 -07003403 Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
3404 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
3405 return;
3406 } catch (InvalidKeySpecException e) {
3407 Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
3408 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root38cf8862010-09-26 14:18:51 -07003409 return;
3410 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003411 }
Kenny Root38cf8862010-09-26 14:18:51 -07003412
Kenny Rootaf9d6672010-10-08 09:21:39 -07003413 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003414 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003415 mConnector.execute("obb", "mount", mObbState.canonicalPath, new SensitiveArg(hashedKey),
Jeff Sharkey56cd6462013-06-07 15:09:15 -07003416 mObbState.ownerGid);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003417 } catch (NativeDaemonConnectorException e) {
3418 int code = e.getCode();
3419 if (code != VoldResponseCode.OpFailedStorageBusy) {
3420 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003421 }
3422 }
3423
Kenny Rootaf9d6672010-10-08 09:21:39 -07003424 if (rc == StorageResultCode.OperationSucceeded) {
3425 if (DEBUG_OBB)
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003426 Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003427
3428 synchronized (mObbMounts) {
3429 addObbStateLocked(mObbState);
3430 }
3431
3432 sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
Kenny Root02c87302010-07-01 08:10:18 -07003433 } else {
Kenny Root05105f72010-09-22 17:29:43 -07003434 Slog.e(TAG, "Couldn't mount OBB file: " + rc);
Kenny Roota02b8b02010-08-05 16:14:17 -07003435
Kenny Rootaf9d6672010-10-08 09:21:39 -07003436 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
Kenny Root02c87302010-07-01 08:10:18 -07003437 }
3438 }
3439
Jason parks5af0b912010-11-29 09:05:25 -06003440 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003441 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003442 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root02c87302010-07-01 08:10:18 -07003443 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003444
3445 @Override
3446 public String toString() {
3447 StringBuilder sb = new StringBuilder();
3448 sb.append("MountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003449 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003450 sb.append('}');
3451 return sb.toString();
3452 }
3453 }
3454
3455 class UnmountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003456 private final boolean mForceUnmount;
Kenny Roota02b8b02010-08-05 16:14:17 -07003457
3458 UnmountObbAction(ObbState obbState, boolean force) {
3459 super(obbState);
3460 mForceUnmount = force;
3461 }
3462
Jason parks5af0b912010-11-29 09:05:25 -06003463 @Override
Kenny Root38cf8862010-09-26 14:18:51 -07003464 public void handleExecute() throws IOException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003465 waitForReady();
3466 warnOnNotMounted();
3467
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003468 final ObbState existingState;
Kenny Root38cf8862010-09-26 14:18:51 -07003469 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003470 existingState = mObbPathToStateMap.get(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003471 }
Kenny Root38cf8862010-09-26 14:18:51 -07003472
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003473 if (existingState == null) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003474 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
3475 return;
3476 }
3477
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003478 if (existingState.ownerGid != mObbState.ownerGid) {
3479 Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
3480 + " (owned by GID " + existingState.ownerGid + ")");
Kenny Rootaf9d6672010-10-08 09:21:39 -07003481 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3482 return;
3483 }
3484
Kenny Rootaf9d6672010-10-08 09:21:39 -07003485 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003486 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003487 final Command cmd = new Command("obb", "unmount", mObbState.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08003488 if (mForceUnmount) {
3489 cmd.appendArg("force");
3490 }
3491 mConnector.execute(cmd);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003492 } catch (NativeDaemonConnectorException e) {
3493 int code = e.getCode();
3494 if (code == VoldResponseCode.OpFailedStorageBusy) {
3495 rc = StorageResultCode.OperationFailedStorageBusy;
3496 } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
3497 // If it's not mounted then we've already won.
3498 rc = StorageResultCode.OperationSucceeded;
3499 } else {
3500 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003501 }
3502 }
3503
Kenny Rootaf9d6672010-10-08 09:21:39 -07003504 if (rc == StorageResultCode.OperationSucceeded) {
3505 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003506 removeObbStateLocked(existingState);
Kenny Root38cf8862010-09-26 14:18:51 -07003507 }
3508
Kenny Rootaf9d6672010-10-08 09:21:39 -07003509 sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
Kenny Roota02b8b02010-08-05 16:14:17 -07003510 } else {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003511 Slog.w(TAG, "Could not unmount OBB: " + existingState);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003512 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
Kenny Roota02b8b02010-08-05 16:14:17 -07003513 }
3514 }
3515
Jason parks5af0b912010-11-29 09:05:25 -06003516 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003517 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003518 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Roota02b8b02010-08-05 16:14:17 -07003519 }
3520
3521 @Override
3522 public String toString() {
3523 StringBuilder sb = new StringBuilder();
3524 sb.append("UnmountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003525 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003526 sb.append(",force=");
3527 sb.append(mForceUnmount);
Kenny Roota02b8b02010-08-05 16:14:17 -07003528 sb.append('}');
3529 return sb.toString();
3530 }
Kenny Root02c87302010-07-01 08:10:18 -07003531 }
Kenny Root38cf8862010-09-26 14:18:51 -07003532
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003533 private static class Callbacks extends Handler {
3534 private static final int MSG_STORAGE_STATE_CHANGED = 1;
3535 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003536 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
3537 private static final int MSG_VOLUME_FORGOTTEN = 4;
3538 private static final int MSG_DISK_SCANNED = 5;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003539 private static final int MSG_DISK_DESTROYED = 6;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003540
3541 private final RemoteCallbackList<IMountServiceListener>
3542 mCallbacks = new RemoteCallbackList<>();
3543
3544 public Callbacks(Looper looper) {
3545 super(looper);
3546 }
3547
3548 public void register(IMountServiceListener callback) {
3549 mCallbacks.register(callback);
3550 }
3551
3552 public void unregister(IMountServiceListener callback) {
3553 mCallbacks.unregister(callback);
3554 }
3555
3556 @Override
3557 public void handleMessage(Message msg) {
3558 final SomeArgs args = (SomeArgs) msg.obj;
3559 final int n = mCallbacks.beginBroadcast();
3560 for (int i = 0; i < n; i++) {
3561 final IMountServiceListener callback = mCallbacks.getBroadcastItem(i);
3562 try {
3563 invokeCallback(callback, msg.what, args);
3564 } catch (RemoteException ignored) {
3565 }
3566 }
3567 mCallbacks.finishBroadcast();
3568 args.recycle();
3569 }
3570
3571 private void invokeCallback(IMountServiceListener callback, int what, SomeArgs args)
3572 throws RemoteException {
3573 switch (what) {
3574 case MSG_STORAGE_STATE_CHANGED: {
3575 callback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
3576 (String) args.arg3);
3577 break;
3578 }
3579 case MSG_VOLUME_STATE_CHANGED: {
3580 callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
3581 break;
3582 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07003583 case MSG_VOLUME_RECORD_CHANGED: {
3584 callback.onVolumeRecordChanged((VolumeRecord) args.arg1);
3585 break;
3586 }
3587 case MSG_VOLUME_FORGOTTEN: {
3588 callback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003589 break;
3590 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003591 case MSG_DISK_SCANNED: {
3592 callback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003593 break;
3594 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003595 case MSG_DISK_DESTROYED: {
3596 callback.onDiskDestroyed((DiskInfo) args.arg1);
3597 break;
3598 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003599 }
3600 }
3601
3602 private void notifyStorageStateChanged(String path, String oldState, String newState) {
3603 final SomeArgs args = SomeArgs.obtain();
3604 args.arg1 = path;
3605 args.arg2 = oldState;
3606 args.arg3 = newState;
3607 obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
3608 }
3609
3610 private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
3611 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003612 args.arg1 = vol.clone();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003613 args.argi2 = oldState;
3614 args.argi3 = newState;
3615 obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
3616 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003617
Jeff Sharkey50a05452015-04-29 11:24:52 -07003618 private void notifyVolumeRecordChanged(VolumeRecord rec) {
3619 final SomeArgs args = SomeArgs.obtain();
3620 args.arg1 = rec.clone();
3621 obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
3622 }
3623
3624 private void notifyVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003625 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003626 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003627 obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003628 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003629
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003630 private void notifyDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003631 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003632 args.arg1 = disk.clone();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003633 args.argi2 = volumeCount;
3634 obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003635 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003636
3637 private void notifyDiskDestroyed(DiskInfo disk) {
3638 final SomeArgs args = SomeArgs.obtain();
3639 args.arg1 = disk.clone();
3640 obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
3641 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003642 }
3643
Kenny Root38cf8862010-09-26 14:18:51 -07003644 @Override
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003645 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
3646 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
3647
3648 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003649 synchronized (mLock) {
3650 pw.println("Disks:");
3651 pw.increaseIndent();
3652 for (int i = 0; i < mDisks.size(); i++) {
3653 final DiskInfo disk = mDisks.valueAt(i);
3654 disk.dump(pw);
3655 }
3656 pw.decreaseIndent();
3657
3658 pw.println();
3659 pw.println("Volumes:");
3660 pw.increaseIndent();
3661 for (int i = 0; i < mVolumes.size(); i++) {
3662 final VolumeInfo vol = mVolumes.valueAt(i);
3663 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue;
3664 vol.dump(pw);
3665 }
3666 pw.decreaseIndent();
3667
3668 pw.println();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003669 pw.println("Records:");
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003670 pw.increaseIndent();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003671 for (int i = 0; i < mRecords.size(); i++) {
3672 final VolumeRecord note = mRecords.valueAt(i);
3673 note.dump(pw);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003674 }
3675 pw.decreaseIndent();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07003676
3677 pw.println();
3678 pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07003679 pw.println("Force adoptable: " + mForceAdoptable);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08003680 pw.println();
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003681 pw.println("Local unlocked users: " + Arrays.toString(mLocalUnlockedUsers));
3682 pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003683 }
Kenny Root38cf8862010-09-26 14:18:51 -07003684
Kenny Root38cf8862010-09-26 14:18:51 -07003685 synchronized (mObbMounts) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003686 pw.println();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003687 pw.println("mObbMounts:");
3688 pw.increaseIndent();
3689 final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet()
3690 .iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003691 while (binders.hasNext()) {
3692 Entry<IBinder, List<ObbState>> e = binders.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003693 pw.println(e.getKey() + ":");
3694 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003695 final List<ObbState> obbStates = e.getValue();
Kenny Root38cf8862010-09-26 14:18:51 -07003696 for (final ObbState obbState : obbStates) {
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003697 pw.println(obbState);
Kenny Root38cf8862010-09-26 14:18:51 -07003698 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003699 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003700 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003701 pw.decreaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003702
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003703 pw.println();
3704 pw.println("mObbPathToStateMap:");
3705 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003706 final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
3707 while (maps.hasNext()) {
3708 final Entry<String, ObbState> e = maps.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003709 pw.print(e.getKey());
3710 pw.print(" -> ");
3711 pw.println(e.getValue());
Kenny Rootaf9d6672010-10-08 09:21:39 -07003712 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003713 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003714 }
Kenny Root4161f9b2011-07-13 09:48:33 -07003715
Robert Greenwalt470fd722012-01-18 12:51:15 -08003716 pw.println();
Jeff Sharkey5b0e5202015-12-18 17:18:09 -07003717 pw.println("mConnector:");
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003718 pw.increaseIndent();
Robert Greenwalt470fd722012-01-18 12:51:15 -08003719 mConnector.dump(fd, pw, args);
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003720 pw.decreaseIndent();
Christopher Tate7265abe2014-11-21 13:54:45 -08003721
Christopher Tate7265abe2014-11-21 13:54:45 -08003722 pw.println();
Jeff Sharkey5b0e5202015-12-18 17:18:09 -07003723 pw.println("mCryptConnector:");
3724 pw.increaseIndent();
3725 mCryptConnector.dump(fd, pw, args);
3726 pw.decreaseIndent();
3727
3728 pw.println();
Christopher Tate7265abe2014-11-21 13:54:45 -08003729 pw.print("Last maintenance: ");
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07003730 pw.println(TimeUtils.formatForLogging(mLastMaintenance));
Kenny Root38cf8862010-09-26 14:18:51 -07003731 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003732
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003733 /** {@inheritDoc} */
Jeff Sharkey48877892015-03-18 11:27:19 -07003734 @Override
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003735 public void monitor() {
3736 if (mConnector != null) {
3737 mConnector.monitor();
3738 }
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07003739 if (mCryptConnector != null) {
3740 mCryptConnector.monitor();
3741 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003742 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003743
3744 private final class MountServiceInternalImpl extends MountServiceInternal {
3745 // Not guarded by a lock.
3746 private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
3747 new CopyOnWriteArrayList<>();
3748
3749 @Override
3750 public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
3751 // No locking - CopyOnWriteArrayList
3752 mPolicies.add(policy);
3753 }
3754
3755 @Override
3756 public void onExternalStoragePolicyChanged(int uid, String packageName) {
3757 final int mountMode = getExternalStorageMountMode(uid, packageName);
3758 remountUidExternalStorage(uid, mountMode);
3759 }
3760
3761 @Override
3762 public int getExternalStorageMountMode(int uid, String packageName) {
3763 // No locking - CopyOnWriteArrayList
3764 int mountMode = Integer.MAX_VALUE;
3765 for (ExternalStorageMountPolicy policy : mPolicies) {
3766 final int policyMode = policy.getMountMode(uid, packageName);
3767 if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
3768 return Zygote.MOUNT_EXTERNAL_NONE;
3769 }
3770 mountMode = Math.min(mountMode, policyMode);
3771 }
3772 if (mountMode == Integer.MAX_VALUE) {
3773 return Zygote.MOUNT_EXTERNAL_NONE;
3774 }
3775 return mountMode;
3776 }
3777
3778 public boolean hasExternalStorage(int uid, String packageName) {
Amith Yamasani2bd5cff2015-07-22 14:42:31 -07003779 // No need to check for system uid. This avoids a deadlock between
3780 // PackageManagerService and AppOpsService.
3781 if (uid == Process.SYSTEM_UID) {
3782 return true;
3783 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003784 // No locking - CopyOnWriteArrayList
3785 for (ExternalStorageMountPolicy policy : mPolicies) {
3786 final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
3787 if (!policyHasStorage) {
3788 return false;
3789 }
3790 }
3791 return true;
3792 }
3793 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003794}