blob: 0023e4bef77c798153cb50527d4d53abff90926f [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 Sharkeyab15c392016-05-05 11:45:01 -0600181 public void onSwitchUser(int userHandle) {
182 mMountService.mCurrentUserId = userHandle;
183 }
184
185 @Override
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700186 public void onUnlockUser(int userHandle) {
187 mMountService.onUnlockUser(userHandle);
Jeff Sharkey48877892015-03-18 11:27:19 -0700188 }
189
190 @Override
191 public void onCleanupUser(int userHandle) {
192 mMountService.onCleanupUser(userHandle);
193 }
Jeff Sharkey56e62932015-03-21 20:41:00 -0700194 }
195
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800196 private static final boolean DEBUG_EVENTS = false;
Kenny Rootb7db2722011-01-25 16:39:35 -0800197 private static final boolean DEBUG_OBB = false;
Kenny Root02c87302010-07-01 08:10:18 -0700198
Kenny Root07714d42011-08-17 17:49:28 -0700199 // Disable this since it messes up long-running cryptfs operations.
200 private static final boolean WATCHDOG_ENABLE = false;
201
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 private static final String TAG = "MountService";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700203
Jeff Sharkey9756d752015-05-14 21:07:42 -0700204 private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700205 private static final String TAG_STORAGE_TRIM = "storage_trim";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206
Kenny Root305bcbf2010-09-03 07:56:38 -0700207 private static final String VOLD_TAG = "VoldConnector";
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700208 private static final String CRYPTD_TAG = "CryptdConnector";
Kenny Root305bcbf2010-09-03 07:56:38 -0700209
Kenny Rootcf0b38c2011-03-22 14:17:59 -0700210 /** Maximum number of ASEC containers allowed to be mounted. */
211 private static final int MAX_CONTAINERS = 250;
212
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700213 /** Magic value sent by MoveTask.cpp */
214 private static final int MOVE_STATUS_COPY_FINISHED = 82;
215
San Mehat4270e1e2010-01-29 05:32:19 -0800216 /*
217 * Internal vold response code constants
218 */
San Mehat22dd86e2010-01-12 12:21:18 -0800219 class VoldResponseCode {
San Mehat4270e1e2010-01-29 05:32:19 -0800220 /*
221 * 100 series - Requestion action was initiated; expect another reply
222 * before proceeding with a new command.
223 */
San Mehat22dd86e2010-01-12 12:21:18 -0800224 public static final int VolumeListResult = 110;
225 public static final int AsecListResult = 111;
San Mehatc1b4ce92010-02-16 17:13:03 -0800226 public static final int StorageUsersListResult = 112;
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700227 public static final int CryptfsGetfieldResult = 113;
San Mehat22dd86e2010-01-12 12:21:18 -0800228
San Mehat4270e1e2010-01-29 05:32:19 -0800229 /*
230 * 200 series - Requestion action has been successfully completed.
231 */
232 public static final int ShareStatusResult = 210;
San Mehat22dd86e2010-01-12 12:21:18 -0800233 public static final int AsecPathResult = 211;
San Mehat4270e1e2010-01-29 05:32:19 -0800234 public static final int ShareEnabledResult = 212;
San Mehat22dd86e2010-01-12 12:21:18 -0800235
San Mehat4270e1e2010-01-29 05:32:19 -0800236 /*
237 * 400 series - Command was accepted, but the requested action
238 * did not take place.
239 */
240 public static final int OpFailedNoMedia = 401;
241 public static final int OpFailedMediaBlank = 402;
242 public static final int OpFailedMediaCorrupt = 403;
243 public static final int OpFailedVolNotMounted = 404;
San Mehatd9709982010-02-18 11:43:03 -0800244 public static final int OpFailedStorageBusy = 405;
San Mehat2d66cef2010-03-23 11:12:52 -0700245 public static final int OpFailedStorageNotFound = 406;
San Mehat4270e1e2010-01-29 05:32:19 -0800246
247 /*
248 * 600 series - Unsolicited broadcasts.
249 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700250 public static final int DISK_CREATED = 640;
251 public static final int DISK_SIZE_CHANGED = 641;
252 public static final int DISK_LABEL_CHANGED = 642;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700253 public static final int DISK_SCANNED = 643;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700254 public static final int DISK_SYS_PATH_CHANGED = 644;
Jeff Sharkey48877892015-03-18 11:27:19 -0700255 public static final int DISK_DESTROYED = 649;
256
257 public static final int VOLUME_CREATED = 650;
258 public static final int VOLUME_STATE_CHANGED = 651;
259 public static final int VOLUME_FS_TYPE_CHANGED = 652;
260 public static final int VOLUME_FS_UUID_CHANGED = 653;
261 public static final int VOLUME_FS_LABEL_CHANGED = 654;
262 public static final int VOLUME_PATH_CHANGED = 655;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700263 public static final int VOLUME_INTERNAL_PATH_CHANGED = 656;
Jeff Sharkey48877892015-03-18 11:27:19 -0700264 public static final int VOLUME_DESTROYED = 659;
Svetoslavf23b64d2013-04-25 14:45:54 -0700265
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700266 public static final int MOVE_STATUS = 660;
Jeff Sharkey9756d752015-05-14 21:07:42 -0700267 public static final int BENCHMARK_RESULT = 661;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700268 public static final int TRIM_RESULT = 662;
San Mehat22dd86e2010-01-12 12:21:18 -0800269 }
270
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700271 private static final int VERSION_INIT = 1;
272 private static final int VERSION_ADD_PRIMARY = 2;
Jeff Sharkeyfced5342015-05-10 14:53:34 -0700273 private static final int VERSION_FIX_PRIMARY = 3;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700274
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700275 private static final String TAG_VOLUMES = "volumes";
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700276 private static final String ATTR_VERSION = "version";
277 private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid";
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700278 private static final String ATTR_FORCE_ADOPTABLE = "forceAdoptable";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700279 private static final String TAG_VOLUME = "volume";
280 private static final String ATTR_TYPE = "type";
281 private static final String ATTR_FS_UUID = "fsUuid";
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700282 private static final String ATTR_PART_GUID = "partGuid";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700283 private static final String ATTR_NICKNAME = "nickname";
284 private static final String ATTR_USER_FLAGS = "userFlags";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700285 private static final String ATTR_CREATED_MILLIS = "createdMillis";
286 private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis";
287 private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700288
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700289 private final AtomicFile mSettingsFile;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700290
Jeff Sharkey48877892015-03-18 11:27:19 -0700291 /**
292 * <em>Never</em> hold the lock while performing downcalls into vold, since
293 * unsolicited events can suddenly appear to update data structures.
294 */
295 private final Object mLock = new Object();
296
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700297 /** Set of users that we know are unlocked. */
Jeff Sharkey48877892015-03-18 11:27:19 -0700298 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700299 private int[] mLocalUnlockedUsers = EmptyArray.INT;
300 /** Set of users that system knows are unlocked. */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800301 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700302 private int[] mSystemUnlockedUsers = EmptyArray.INT;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700303
304 /** Map from disk ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700305 @GuardedBy("mLock")
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700306 private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700307 /** Map from volume ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700308 @GuardedBy("mLock")
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700309 private final ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
Jeff Sharkey48877892015-03-18 11:27:19 -0700310
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700311 /** Map from UUID to record */
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700312 @GuardedBy("mLock")
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700313 private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>();
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700314 @GuardedBy("mLock")
315 private String mPrimaryStorageUuid;
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700316 @GuardedBy("mLock")
317 private boolean mForceAdoptable;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700318
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700319 /** Map from disk ID to latches */
320 @GuardedBy("mLock")
321 private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
322
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700323 @GuardedBy("mLock")
324 private IPackageMoveObserver mMoveCallback;
325 @GuardedBy("mLock")
326 private String mMoveTargetUuid;
327
Jeff Sharkeyab15c392016-05-05 11:45:01 -0600328 private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
329
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700330 private VolumeInfo findVolumeByIdOrThrow(String id) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700331 synchronized (mLock) {
332 final VolumeInfo vol = mVolumes.get(id);
333 if (vol != null) {
334 return vol;
335 }
336 }
337 throw new IllegalArgumentException("No volume found for ID " + id);
338 }
339
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700340 private String findVolumeIdForPathOrThrow(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700341 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700342 for (int i = 0; i < mVolumes.size(); i++) {
343 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700344 if (vol.path != null && path.startsWith(vol.path)) {
345 return vol.id;
Jeff Sharkey48877892015-03-18 11:27:19 -0700346 }
347 }
348 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700349 throw new IllegalArgumentException("No volume found for path " + path);
Jeff Sharkey48877892015-03-18 11:27:19 -0700350 }
351
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700352 private VolumeRecord findRecordForPath(String path) {
353 synchronized (mLock) {
354 for (int i = 0; i < mVolumes.size(); i++) {
355 final VolumeInfo vol = mVolumes.valueAt(i);
356 if (vol.path != null && path.startsWith(vol.path)) {
357 return mRecords.get(vol.fsUuid);
358 }
359 }
360 }
361 return null;
362 }
363
364 private String scrubPath(String path) {
365 if (path.startsWith(Environment.getDataDirectory().getAbsolutePath())) {
366 return "internal";
367 }
368 final VolumeRecord rec = findRecordForPath(path);
369 if (rec == null || rec.createdMillis == 0) {
370 return "unknown";
371 } else {
372 return "ext:" + (int) ((System.currentTimeMillis() - rec.createdMillis)
373 / DateUtils.WEEK_IN_MILLIS) + "w";
374 }
375 }
376
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700377 private @Nullable VolumeInfo findStorageForUuid(String volumeUuid) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700378 final StorageManager storage = mContext.getSystemService(StorageManager.class);
379 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700380 return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL);
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700381 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
382 return storage.getPrimaryPhysicalVolume();
383 } else {
384 return storage.findEmulatedForPrivate(storage.findVolumeByUuid(volumeUuid));
385 }
386 }
387
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700388 private boolean shouldBenchmark() {
389 final long benchInterval = Settings.Global.getLong(mContext.getContentResolver(),
390 Settings.Global.STORAGE_BENCHMARK_INTERVAL, DateUtils.WEEK_IN_MILLIS);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700391 if (benchInterval == -1) {
392 return false;
393 } else if (benchInterval == 0) {
394 return true;
395 }
396
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700397 synchronized (mLock) {
398 for (int i = 0; i < mVolumes.size(); i++) {
399 final VolumeInfo vol = mVolumes.valueAt(i);
400 final VolumeRecord rec = mRecords.get(vol.fsUuid);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700401 if (vol.isMountedWritable() && rec != null) {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700402 final long benchAge = System.currentTimeMillis() - rec.lastBenchMillis;
403 if (benchAge >= benchInterval) {
404 return true;
405 }
406 }
407 }
408 return false;
409 }
410 }
411
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700412 private CountDownLatch findOrCreateDiskScanLatch(String diskId) {
413 synchronized (mLock) {
414 CountDownLatch latch = mDiskScanLatches.get(diskId);
415 if (latch == null) {
416 latch = new CountDownLatch(1);
417 mDiskScanLatches.put(diskId, latch);
418 }
419 return latch;
420 }
421 }
422
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800423 private static String escapeNull(String arg) {
424 if (TextUtils.isEmpty(arg)) {
425 return "!";
426 } else {
427 if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
428 throw new IllegalArgumentException(arg);
429 }
430 return arg;
431 }
432 }
433
Paul Lawrence8e397362014-01-27 15:22:30 -0800434 /** List of crypto types.
435 * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
436 * corresponding commands in CommandListener.cpp */
437 public static final String[] CRYPTO_TYPES
438 = { "password", "default", "pattern", "pin" };
439
Brian Carlstrom7395a8a2014-04-28 22:11:01 -0700440 private final Context mContext;
Jeff Sharkeycd575992016-03-29 14:12:49 -0600441
Brian Carlstromdfad99a2014-05-07 15:21:14 -0700442 private final NativeDaemonConnector mConnector;
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700443 private final NativeDaemonConnector mCryptConnector;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700444
Jeff Sharkeycd575992016-03-29 14:12:49 -0600445 private final Thread mConnectorThread;
446 private final Thread mCryptConnectorThread;
447
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700448 private volatile boolean mSystemReady = false;
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900449 private volatile boolean mBootCompleted = false;
Jeff Sharkey48877892015-03-18 11:27:19 -0700450 private volatile boolean mDaemonConnected = false;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700451
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700452 private PackageManagerService mPms;
453
454 private final Callbacks mCallbacks;
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700455 private final LockPatternUtils mLockPatternUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -0700456
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700457 // Two connectors - mConnector & mCryptConnector
458 private final CountDownLatch mConnectedSignal = new CountDownLatch(2);
Jeff Sharkey0be607c2012-11-14 14:39:19 -0800459 private final CountDownLatch mAsecsScanned = new CountDownLatch(1);
Jeff Sharkey48877892015-03-18 11:27:19 -0700460
461 private final Object mUnmountLock = new Object();
462 @GuardedBy("mUnmountLock")
463 private CountDownLatch mUnmountSignal;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800464
San Mehat6cdd9c02010-02-09 14:45:20 -0800465 /**
466 * Private hash of currently mounted secure containers.
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800467 * Used as a lock in methods to manipulate secure containers.
San Mehat6cdd9c02010-02-09 14:45:20 -0800468 */
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800469 final private HashSet<String> mAsecMountSet = new HashSet<String>();
San Mehat6cdd9c02010-02-09 14:45:20 -0800470
Kenny Root02c87302010-07-01 08:10:18 -0700471 /**
Kenny Root3b1abba2010-10-13 15:00:07 -0700472 * The size of the crypto algorithm key in bits for OBB files. Currently
473 * Twofish is used which takes 128-bit keys.
474 */
475 private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
476
477 /**
478 * The number of times to run SHA1 in the PBKDF2 function for OBB files.
479 * 1024 is reasonably secure and not too slow.
480 */
481 private static final int PBKDF2_HASH_ROUNDS = 1024;
482
483 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700484 * Mounted OBB tracking information. Used to track the current state of all
485 * OBBs.
Kenny Root02c87302010-07-01 08:10:18 -0700486 */
Kenny Root735de3b2010-09-30 14:11:39 -0700487 final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700488
489 /** Map from raw paths to {@link ObbState}. */
Kenny Roota02b8b02010-08-05 16:14:17 -0700490 final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
491
Svet Ganov6ee871e2015-07-10 14:29:33 -0700492 // Not guarded by a lock.
493 private final MountServiceInternalImpl mMountServiceInternal = new MountServiceInternalImpl();
494
Kenny Roota02b8b02010-08-05 16:14:17 -0700495 class ObbState implements IBinder.DeathRecipient {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700496 public ObbState(String rawPath, String canonicalPath, int callingUid,
497 IObbActionListener token, int nonce) {
498 this.rawPath = rawPath;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700499 this.canonicalPath = canonicalPath;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700500
501 this.ownerGid = UserHandle.getSharedAppGid(callingUid);
Kenny Rootaf9d6672010-10-08 09:21:39 -0700502 this.token = token;
503 this.nonce = nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700504 }
505
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700506 final String rawPath;
507 final String canonicalPath;
Kenny Roota02b8b02010-08-05 16:14:17 -0700508
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700509 final int ownerGid;
Kenny Roota02b8b02010-08-05 16:14:17 -0700510
Kenny Rootaf9d6672010-10-08 09:21:39 -0700511 // Token of remote Binder caller
512 final IObbActionListener token;
513
514 // Identifier to pass back to the token
515 final int nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700516
Kenny Root735de3b2010-09-30 14:11:39 -0700517 public IBinder getBinder() {
518 return token.asBinder();
519 }
520
Kenny Roota02b8b02010-08-05 16:14:17 -0700521 @Override
522 public void binderDied() {
523 ObbAction action = new UnmountObbAction(this, true);
524 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root735de3b2010-09-30 14:11:39 -0700525 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700526
Kenny Root5919ac62010-10-05 09:49:40 -0700527 public void link() throws RemoteException {
528 getBinder().linkToDeath(this, 0);
529 }
530
531 public void unlink() {
Kenny Root735de3b2010-09-30 14:11:39 -0700532 getBinder().unlinkToDeath(this, 0);
Kenny Roota02b8b02010-08-05 16:14:17 -0700533 }
Kenny Root38cf8862010-09-26 14:18:51 -0700534
535 @Override
536 public String toString() {
537 StringBuilder sb = new StringBuilder("ObbState{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700538 sb.append("rawPath=").append(rawPath);
539 sb.append(",canonicalPath=").append(canonicalPath);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700540 sb.append(",ownerGid=").append(ownerGid);
541 sb.append(",token=").append(token);
542 sb.append(",binder=").append(getBinder());
Kenny Root38cf8862010-09-26 14:18:51 -0700543 sb.append('}');
544 return sb.toString();
545 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700546 }
547
548 // OBB Action Handler
549 final private ObbActionHandler mObbActionHandler;
550
551 // OBB action handler messages
552 private static final int OBB_RUN_ACTION = 1;
553 private static final int OBB_MCS_BOUND = 2;
554 private static final int OBB_MCS_UNBIND = 3;
555 private static final int OBB_MCS_RECONNECT = 4;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700556 private static final int OBB_FLUSH_MOUNT_STATE = 5;
Kenny Roota02b8b02010-08-05 16:14:17 -0700557
558 /*
559 * Default Container Service information
560 */
561 static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
562 "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
563
564 final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
565
566 class DefaultContainerConnection implements ServiceConnection {
Jeff Sharkey48877892015-03-18 11:27:19 -0700567 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700568 public void onServiceConnected(ComponentName name, IBinder service) {
569 if (DEBUG_OBB)
570 Slog.i(TAG, "onServiceConnected");
571 IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
572 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
573 }
574
Jeff Sharkey48877892015-03-18 11:27:19 -0700575 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700576 public void onServiceDisconnected(ComponentName name) {
577 if (DEBUG_OBB)
578 Slog.i(TAG, "onServiceDisconnected");
579 }
580 };
581
582 // Used in the ObbActionHandler
583 private IMediaContainerService mContainerService = null;
Kenny Root02c87302010-07-01 08:10:18 -0700584
Christopher Tate7265abe2014-11-21 13:54:45 -0800585 // Last fstrim operation tracking
586 private static final String LAST_FSTRIM_FILE = "last-fstrim";
587 private final File mLastMaintenanceFile;
588 private long mLastMaintenance;
589
Kenny Root02c87302010-07-01 08:10:18 -0700590 // Handler messages
Jeff Sharkey48877892015-03-18 11:27:19 -0700591 private static final int H_SYSTEM_READY = 1;
592 private static final int H_DAEMON_CONNECTED = 2;
593 private static final int H_SHUTDOWN = 3;
594 private static final int H_FSTRIM = 4;
595 private static final int H_VOLUME_MOUNT = 5;
596 private static final int H_VOLUME_BROADCAST = 6;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700597 private static final int H_INTERNAL_BROADCAST = 7;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700598 private static final int H_VOLUME_UNMOUNT = 8;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800599 private static final int H_PARTITION_FORGET = 9;
600 private static final int H_RESET = 10;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800601
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400602 class MountServiceHandler extends Handler {
Jeff Sharkey48877892015-03-18 11:27:19 -0700603 public MountServiceHandler(Looper looper) {
604 super(looper);
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400605 }
606
Jason parks5af0b912010-11-29 09:05:25 -0600607 @Override
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800608 public void handleMessage(Message msg) {
609 switch (msg.what) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700610 case H_SYSTEM_READY: {
Jeff Sharkey48877892015-03-18 11:27:19 -0700611 handleSystemReady();
612 break;
613 }
614 case H_DAEMON_CONNECTED: {
615 handleDaemonConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700616 break;
617 }
Christopher Tated417d622013-08-19 16:14:25 -0700618 case H_FSTRIM: {
Jeff Sharkey1783f142015-04-17 10:52:51 -0700619 if (!isReady()) {
620 Slog.i(TAG, "fstrim requested, but no daemon connection yet; trying again");
Christopher Tate7618db12015-04-28 16:32:55 -0700621 sendMessageDelayed(obtainMessage(H_FSTRIM, msg.obj),
622 DateUtils.SECOND_IN_MILLIS);
623 break;
Jeff Sharkey1783f142015-04-17 10:52:51 -0700624 }
625
Christopher Tated417d622013-08-19 16:14:25 -0700626 Slog.i(TAG, "Running fstrim idle maintenance");
Christopher Tate7265abe2014-11-21 13:54:45 -0800627
628 // Remember when we kicked it off
629 try {
630 mLastMaintenance = System.currentTimeMillis();
631 mLastMaintenanceFile.setLastModified(mLastMaintenance);
632 } catch (Exception e) {
633 Slog.e(TAG, "Unable to record last fstrim!");
634 }
635
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700636 final boolean shouldBenchmark = shouldBenchmark();
Christopher Tated417d622013-08-19 16:14:25 -0700637 try {
638 // This method must be run on the main (handler) thread,
639 // so it is safe to directly call into vold.
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700640 mConnector.execute("fstrim", shouldBenchmark ? "dotrimbench" : "dotrim");
Christopher Tated417d622013-08-19 16:14:25 -0700641 } catch (NativeDaemonConnectorException ndce) {
642 Slog.e(TAG, "Failed to run fstrim!");
643 }
Christopher Tate7265abe2014-11-21 13:54:45 -0800644
Christopher Tated417d622013-08-19 16:14:25 -0700645 // invoke the completion callback, if any
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700646 // TODO: fstrim is non-blocking, so remove this useless callback
Christopher Tated417d622013-08-19 16:14:25 -0700647 Runnable callback = (Runnable) msg.obj;
648 if (callback != null) {
649 callback.run();
650 }
651 break;
652 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700653 case H_SHUTDOWN: {
654 final IMountShutdownObserver obs = (IMountShutdownObserver) msg.obj;
655 boolean success = false;
656 try {
657 success = mConnector.execute("volume", "shutdown").isClassOk();
658 } catch (NativeDaemonConnectorException ignored) {
659 }
660 if (obs != null) {
661 try {
662 obs.onShutDownComplete(success ? 0 : -1);
663 } catch (RemoteException ignored) {
664 }
665 }
666 break;
667 }
668 case H_VOLUME_MOUNT: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700669 final VolumeInfo vol = (VolumeInfo) msg.obj;
Jeff Sharkey2e606d72015-07-27 14:19:54 -0700670 if (isMountDisallowed(vol)) {
671 Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");
672 break;
673 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700674 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700675 mConnector.execute("volume", "mount", vol.id, vol.mountFlags,
676 vol.mountUserId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700677 } catch (NativeDaemonConnectorException ignored) {
678 }
679 break;
680 }
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700681 case H_VOLUME_UNMOUNT: {
682 final VolumeInfo vol = (VolumeInfo) msg.obj;
683 unmount(vol.getId());
684 break;
685 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700686 case H_VOLUME_BROADCAST: {
687 final StorageVolume userVol = (StorageVolume) msg.obj;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700688 final String envState = userVol.getState();
689 Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + envState + " to "
Jeff Sharkey48877892015-03-18 11:27:19 -0700690 + userVol.getOwner());
691
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700692 final String action = VolumeInfo.getBroadcastForEnvironment(envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700693 if (action != null) {
694 final Intent intent = new Intent(action,
695 Uri.fromFile(userVol.getPathFile()));
696 intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, userVol);
697 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
698 mContext.sendBroadcastAsUser(intent, userVol.getOwner());
699 }
700 break;
701 }
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700702 case H_INTERNAL_BROADCAST: {
703 // Internal broadcasts aimed at system components, not for
704 // third-party apps.
705 final Intent intent = (Intent) msg.obj;
706 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
707 android.Manifest.permission.WRITE_MEDIA_STORAGE);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800708 break;
709 }
710 case H_PARTITION_FORGET: {
711 final String partGuid = (String) msg.obj;
712 forgetPartition(partGuid);
713 break;
714 }
715 case H_RESET: {
716 resetIfReadyAndConnected();
717 break;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700718 }
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800719 }
720 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700721 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700722
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700723 private final Handler mHandler;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800724
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700725 private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
726 @Override
727 public void onReceive(Context context, Intent intent) {
728 final String action = intent.getAction();
729 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700730 Preconditions.checkArgument(userId >= 0);
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700731
732 try {
733 if (Intent.ACTION_USER_ADDED.equals(action)) {
734 final UserManager um = mContext.getSystemService(UserManager.class);
735 final int userSerialNumber = um.getUserSerialNumber(userId);
736 mConnector.execute("volume", "user_added", userId, userSerialNumber);
737 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700738 synchronized (mVolumes) {
739 final int size = mVolumes.size();
740 for (int i = 0; i < size; i++) {
741 final VolumeInfo vol = mVolumes.valueAt(i);
742 if (vol.mountUserId == userId) {
743 vol.mountUserId = UserHandle.USER_NULL;
744 mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
745 }
746 }
747 }
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700748 mConnector.execute("volume", "user_removed", userId);
749 }
750 } catch (NativeDaemonConnectorException e) {
751 Slog.w(TAG, "Failed to send user details to vold", e);
752 }
753 }
754 };
755
Jeff Sharkey56e62932015-03-21 20:41:00 -0700756 @Override
757 public void waitForAsecScan() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700758 waitForLatch(mAsecsScanned, "mAsecsScanned");
Kenny Root51a573c2012-05-17 13:30:28 -0700759 }
760
San Mehat207e5382010-02-04 20:46:54 -0800761 private void waitForReady() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700762 waitForLatch(mConnectedSignal, "mConnectedSignal");
Kenny Root51a573c2012-05-17 13:30:28 -0700763 }
764
Jeff Sharkey48877892015-03-18 11:27:19 -0700765 private void waitForLatch(CountDownLatch latch, String condition) {
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700766 try {
767 waitForLatch(latch, condition, -1);
768 } catch (TimeoutException ignored) {
769 }
770 }
771
772 private void waitForLatch(CountDownLatch latch, String condition, long timeoutMillis)
773 throws TimeoutException {
774 final long startMillis = SystemClock.elapsedRealtime();
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700775 while (true) {
Kenny Root51a573c2012-05-17 13:30:28 -0700776 try {
777 if (latch.await(5000, TimeUnit.MILLISECONDS)) {
San Mehat207e5382010-02-04 20:46:54 -0800778 return;
Kenny Root51a573c2012-05-17 13:30:28 -0700779 } else {
780 Slog.w(TAG, "Thread " + Thread.currentThread().getName()
Jeff Sharkey48877892015-03-18 11:27:19 -0700781 + " still waiting for " + condition + "...");
San Mehat207e5382010-02-04 20:46:54 -0800782 }
Kenny Root51a573c2012-05-17 13:30:28 -0700783 } catch (InterruptedException e) {
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700784 Slog.w(TAG, "Interrupt while waiting for " + condition);
San Mehat207e5382010-02-04 20:46:54 -0800785 }
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700786 if (timeoutMillis > 0 && SystemClock.elapsedRealtime() > startMillis + timeoutMillis) {
787 throw new TimeoutException("Thread " + Thread.currentThread().getName()
788 + " gave up waiting for " + condition + " after " + timeoutMillis + "ms");
789 }
San Mehat207e5382010-02-04 20:46:54 -0800790 }
San Mehat1f6301e2010-01-07 22:40:27 -0800791 }
Kenny Root02c87302010-07-01 08:10:18 -0700792
Paul Lawrence945490c2014-03-27 16:37:28 +0000793 private boolean isReady() {
794 try {
795 return mConnectedSignal.await(0, TimeUnit.MILLISECONDS);
796 } catch (InterruptedException e) {
797 return false;
798 }
799 }
800
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700801 private void handleSystemReady() {
Jeff Sharkey8924e872015-11-30 12:52:10 -0700802 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800803 resetIfReadyAndConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700804
Jeff Sharkey48877892015-03-18 11:27:19 -0700805 // Start scheduling nominally-daily fstrim operations
Christopher Tate115afda2014-06-06 19:06:26 -0700806 MountServiceIdler.scheduleIdlePass(mContext);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700807 }
808
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700809 /**
810 * MediaProvider has a ton of code that makes assumptions about storage
811 * paths never changing, so we outright kill them to pick up new state.
812 */
813 @Deprecated
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700814 private void killMediaProvider(List<UserInfo> users) {
815 if (users == null) return;
816
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700817 final long token = Binder.clearCallingIdentity();
818 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700819 for (UserInfo user : users) {
820 // System user does not have media provider, so skip.
821 if (user.isSystemOnly()) continue;
822
Jeff Sharkey2a9e3f82015-12-18 10:57:58 -0700823 final ProviderInfo provider = mPms.resolveContentProvider(MediaStore.AUTHORITY,
Jeff Sharkey8a372a02016-03-16 16:25:45 -0600824 PackageManager.MATCH_DIRECT_BOOT_AWARE
825 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
826 user.id);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700827 if (provider != null) {
828 final IActivityManager am = ActivityManagerNative.getDefault();
829 try {
Jeff Sharkey85f449e2016-06-23 09:26:00 -0600830 am.killApplication(provider.applicationInfo.packageName,
831 UserHandle.getAppId(provider.applicationInfo.uid),
832 UserHandle.USER_ALL, "vold reset");
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700833 // We only need to run this once. It will kill all users' media processes.
834 break;
835 } catch (RemoteException e) {
836 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700837 }
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700838 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700839 } finally {
840 Binder.restoreCallingIdentity(token);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700841 }
842 }
843
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800844 private void addInternalVolumeLocked() {
Amith Yamasania7892482015-08-07 11:09:05 -0700845 // Create a stub volume that represents internal storage
846 final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
847 VolumeInfo.TYPE_PRIVATE, null, null);
848 internal.state = VolumeInfo.STATE_MOUNTED;
849 internal.path = Environment.getDataDirectory().getAbsolutePath();
850 mVolumes.put(internal.id, internal);
851 }
852
Jeff Sharkey8924e872015-11-30 12:52:10 -0700853 private void initIfReadyAndConnected() {
854 Slog.d(TAG, "Thinking about init, mSystemReady=" + mSystemReady
855 + ", mDaemonConnected=" + mDaemonConnected);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700856 if (mSystemReady && mDaemonConnected
Paul Lawrence20be5d62016-02-26 13:51:17 -0800857 && !StorageManager.isFileEncryptedNativeOnly()) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700858 // When booting a device without native support, make sure that our
859 // user directories are locked or unlocked based on the current
860 // emulation status.
Paul Lawrence20be5d62016-02-26 13:51:17 -0800861 final boolean initLocked = StorageManager.isFileEncryptedEmulatedOnly();
Paul Crowleyd94ab732016-02-15 06:44:51 +0000862 Slog.d(TAG, "Setting up emulation state, initlocked=" + initLocked);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700863 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Jeff Sharkey8924e872015-11-30 12:52:10 -0700864 for (UserInfo user : users) {
865 try {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700866 if (initLocked) {
867 mCryptConnector.execute("cryptfs", "lock_user_key", user.id);
868 } else {
869 mCryptConnector.execute("cryptfs", "unlock_user_key", user.id,
Paul Crowleyd94ab732016-02-15 06:44:51 +0000870 user.serialNumber, "!", "!");
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700871 }
Jeff Sharkey8924e872015-11-30 12:52:10 -0700872 } catch (NativeDaemonConnectorException e) {
873 Slog.w(TAG, "Failed to init vold", e);
874 }
875 }
876 }
877 }
878
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800879 private void resetIfReadyAndConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700880 Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
881 + ", mDaemonConnected=" + mDaemonConnected);
882 if (mSystemReady && mDaemonConnected) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800883 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700884 killMediaProvider(users);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700885
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700886 final int[] systemUnlockedUsers;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800887 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700888 systemUnlockedUsers = mSystemUnlockedUsers;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700889
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800890 mDisks.clear();
891 mVolumes.clear();
892
893 addInternalVolumeLocked();
894 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700895
Jeff Sharkey48877892015-03-18 11:27:19 -0700896 try {
897 mConnector.execute("volume", "reset");
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700898
899 // Tell vold about all existing and started users
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700900 for (UserInfo user : users) {
901 mConnector.execute("volume", "user_added", user.id, user.serialNumber);
902 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700903 for (int userId : systemUnlockedUsers) {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700904 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey50a05452015-04-29 11:24:52 -0700905 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700906 } catch (NativeDaemonConnectorException e) {
907 Slog.w(TAG, "Failed to reset vold", e);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700908 }
909 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700910 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700911
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700912 private void onUnlockUser(int userId) {
913 Slog.d(TAG, "onUnlockUser " + userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700914
915 // We purposefully block here to make sure that user-specific
916 // staging area is ready so it's ready for zygote-forked apps to
917 // bind mount against.
918 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700919 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700920 } catch (NativeDaemonConnectorException ignored) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700921 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700922
923 // Record user as started so newly mounted volumes kick off events
924 // correctly, then synthesize events for any already-mounted volumes.
925 synchronized (mVolumes) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700926 for (int i = 0; i < mVolumes.size(); i++) {
927 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey46349872015-07-28 10:49:47 -0700928 if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700929 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey48877892015-03-18 11:27:19 -0700930 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700931
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700932 final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
933 mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700934 }
935 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700936 mSystemUnlockedUsers = ArrayUtils.appendInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700937 }
938 }
939
940 private void onCleanupUser(int userId) {
941 Slog.d(TAG, "onCleanupUser " + userId);
942
943 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700944 mConnector.execute("volume", "user_stopped", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700945 } catch (NativeDaemonConnectorException ignored) {
946 }
947
948 synchronized (mVolumes) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700949 mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700950 }
951 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700952
Christopher Tated417d622013-08-19 16:14:25 -0700953 void runIdleMaintenance(Runnable callback) {
954 mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
955 }
956
Christopher Tate7265abe2014-11-21 13:54:45 -0800957 // Binder entry point for kicking off an immediate fstrim
958 @Override
959 public void runMaintenance() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700960 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Christopher Tate7265abe2014-11-21 13:54:45 -0800961 runIdleMaintenance(null);
962 }
963
964 @Override
965 public long lastMaintenance() {
966 return mLastMaintenance;
967 }
968
San Mehat4270e1e2010-01-29 05:32:19 -0800969 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800970 * Callback from NativeDaemonConnector
971 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700972 @Override
San Mehat4270e1e2010-01-29 05:32:19 -0800973 public void onDaemonConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700974 mDaemonConnected = true;
975 mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();
976 }
977
978 private void handleDaemonConnected() {
Jeff Sharkey8924e872015-11-30 12:52:10 -0700979 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800980 resetIfReadyAndConnected();
Jeff Sharkey48877892015-03-18 11:27:19 -0700981
San Mehat4270e1e2010-01-29 05:32:19 -0800982 /*
Jeff Sharkey48877892015-03-18 11:27:19 -0700983 * Now that we've done our initialization, release
984 * the hounds!
San Mehat4270e1e2010-01-29 05:32:19 -0800985 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700986 mConnectedSignal.countDown();
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700987 if (mConnectedSignal.getCount() != 0) {
988 // More daemons need to connect
989 return;
990 }
Mike Lockwood7fa24aa2011-03-23 14:52:34 -0400991
Jeff Sharkey48877892015-03-18 11:27:19 -0700992 // On an encrypted device we can't see system properties yet, so pull
993 // the system locale out of the mount service.
994 if ("".equals(SystemProperties.get("vold.encrypt_progress"))) {
995 copyLocaleFromMountService();
996 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700997
Jeff Sharkey48877892015-03-18 11:27:19 -0700998 // Let package manager load internal ASECs.
999 mPms.scanAvailableAsecs();
Mike Lockwood7fa24aa2011-03-23 14:52:34 -04001000
Jeff Sharkey48877892015-03-18 11:27:19 -07001001 // Notify people waiting for ASECs to be scanned that it's done.
1002 mAsecsScanned.countDown();
San Mehat4270e1e2010-01-29 05:32:19 -08001003 }
1004
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001005 private void copyLocaleFromMountService() {
1006 String systemLocale;
1007 try {
1008 systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
1009 } catch (RemoteException e) {
1010 return;
1011 }
1012 if (TextUtils.isEmpty(systemLocale)) {
1013 return;
1014 }
1015
1016 Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
1017 Locale locale = Locale.forLanguageTag(systemLocale);
1018 Configuration config = new Configuration();
1019 config.setLocale(locale);
1020 try {
Seigo Nonaka4963dfe2016-03-31 20:50:21 +09001021 ActivityManagerNative.getDefault().updatePersistentConfiguration(config);
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001022 } catch (RemoteException e) {
1023 Slog.e(TAG, "Error setting system locale from mount service", e);
1024 }
Elliott Hughes9c33f282014-10-13 12:39:56 -07001025
1026 // Temporary workaround for http://b/17945169.
1027 Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
Narayan Kamathd30dbb82015-01-15 14:48:15 +00001028 SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001029 }
1030
San Mehat4270e1e2010-01-29 05:32:19 -08001031 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001032 * Callback from NativeDaemonConnector
1033 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001034 @Override
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001035 public boolean onCheckHoldWakeLock(int code) {
1036 return false;
1037 }
1038
1039 /**
1040 * Callback from NativeDaemonConnector
1041 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001042 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001043 public boolean onEvent(int code, String raw, String[] cooked) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001044 synchronized (mLock) {
1045 return onEventLocked(code, raw, cooked);
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -08001046 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001047 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001048
Jeff Sharkey48877892015-03-18 11:27:19 -07001049 private boolean onEventLocked(int code, String raw, String[] cooked) {
1050 switch (code) {
1051 case VoldResponseCode.DISK_CREATED: {
1052 if (cooked.length != 3) break;
1053 final String id = cooked[1];
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001054 int flags = Integer.parseInt(cooked[2]);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001055 if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false)
1056 || mForceAdoptable) {
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001057 flags |= DiskInfo.FLAG_ADOPTABLE;
1058 }
Jeff Sharkey6ed74182016-08-23 13:53:53 -06001059 // Adoptable storage isn't currently supported on FBE devices
1060 if (StorageManager.isFileEncryptedNativeOnly()) {
1061 flags &= ~DiskInfo.FLAG_ADOPTABLE;
1062 }
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001063 mDisks.put(id, new DiskInfo(id, flags));
Jeff Sharkey48877892015-03-18 11:27:19 -07001064 break;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001065 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001066 case VoldResponseCode.DISK_SIZE_CHANGED: {
1067 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001068 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001069 if (disk != null) {
1070 disk.size = Long.parseLong(cooked[2]);
San Mehat4270e1e2010-01-29 05:32:19 -08001071 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001072 break;
1073 }
1074 case VoldResponseCode.DISK_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001075 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001076 if (disk != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001077 final StringBuilder builder = new StringBuilder();
1078 for (int i = 2; i < cooked.length; i++) {
1079 builder.append(cooked[i]).append(' ');
1080 }
1081 disk.label = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001082 }
1083 break;
1084 }
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001085 case VoldResponseCode.DISK_SCANNED: {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001086 if (cooked.length != 2) break;
1087 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001088 if (disk != null) {
1089 onDiskScannedLocked(disk);
1090 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -07001091 break;
1092 }
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001093 case VoldResponseCode.DISK_SYS_PATH_CHANGED: {
1094 if (cooked.length != 3) break;
1095 final DiskInfo disk = mDisks.get(cooked[1]);
1096 if (disk != null) {
1097 disk.sysPath = cooked[2];
1098 }
1099 break;
1100 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001101 case VoldResponseCode.DISK_DESTROYED: {
1102 if (cooked.length != 2) break;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07001103 final DiskInfo disk = mDisks.remove(cooked[1]);
1104 if (disk != null) {
1105 mCallbacks.notifyDiskDestroyed(disk);
1106 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001107 break;
1108 }
San Mehat4270e1e2010-01-29 05:32:19 -08001109
Jeff Sharkey48877892015-03-18 11:27:19 -07001110 case VoldResponseCode.VOLUME_CREATED: {
Jeff Sharkey48877892015-03-18 11:27:19 -07001111 final String id = cooked[1];
1112 final int type = Integer.parseInt(cooked[2]);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001113 final String diskId = TextUtils.nullIfEmpty(cooked[3]);
1114 final String partGuid = TextUtils.nullIfEmpty(cooked[4]);
1115
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001116 final DiskInfo disk = mDisks.get(diskId);
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07001117 final VolumeInfo vol = new VolumeInfo(id, type, disk, partGuid);
Jeff Sharkey48877892015-03-18 11:27:19 -07001118 mVolumes.put(id, vol);
1119 onVolumeCreatedLocked(vol);
1120 break;
1121 }
1122 case VoldResponseCode.VOLUME_STATE_CHANGED: {
1123 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001124 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001125 if (vol != null) {
1126 final int oldState = vol.state;
1127 final int newState = Integer.parseInt(cooked[2]);
1128 vol.state = newState;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001129 onVolumeStateChangedLocked(vol, oldState, newState);
Jeff Sharkey48877892015-03-18 11:27:19 -07001130 }
1131 break;
1132 }
1133 case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: {
1134 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001135 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001136 if (vol != null) {
1137 vol.fsType = cooked[2];
1138 }
1139 break;
1140 }
1141 case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
1142 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001143 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001144 if (vol != null) {
1145 vol.fsUuid = cooked[2];
1146 }
1147 break;
1148 }
1149 case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001150 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001151 if (vol != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001152 final StringBuilder builder = new StringBuilder();
1153 for (int i = 2; i < cooked.length; i++) {
1154 builder.append(cooked[i]).append(' ');
1155 }
1156 vol.fsLabel = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001157 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001158 // TODO: notify listeners that label changed
Jeff Sharkey48877892015-03-18 11:27:19 -07001159 break;
1160 }
1161 case VoldResponseCode.VOLUME_PATH_CHANGED: {
1162 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001163 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001164 if (vol != null) {
1165 vol.path = cooked[2];
1166 }
1167 break;
1168 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001169 case VoldResponseCode.VOLUME_INTERNAL_PATH_CHANGED: {
1170 if (cooked.length != 3) break;
1171 final VolumeInfo vol = mVolumes.get(cooked[1]);
1172 if (vol != null) {
1173 vol.internalPath = cooked[2];
1174 }
1175 break;
1176 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001177 case VoldResponseCode.VOLUME_DESTROYED: {
1178 if (cooked.length != 2) break;
1179 mVolumes.remove(cooked[1]);
1180 break;
1181 }
San Mehat4270e1e2010-01-29 05:32:19 -08001182
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001183 case VoldResponseCode.MOVE_STATUS: {
1184 final int status = Integer.parseInt(cooked[1]);
1185 onMoveStatusLocked(status);
1186 break;
1187 }
Jeff Sharkey9756d752015-05-14 21:07:42 -07001188 case VoldResponseCode.BENCHMARK_RESULT: {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001189 if (cooked.length != 7) break;
1190 final String path = cooked[1];
1191 final String ident = cooked[2];
1192 final long create = Long.parseLong(cooked[3]);
1193 final long drop = Long.parseLong(cooked[4]);
1194 final long run = Long.parseLong(cooked[5]);
1195 final long destroy = Long.parseLong(cooked[6]);
1196
Jeff Sharkey9756d752015-05-14 21:07:42 -07001197 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001198 dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
1199 + " " + ident + " " + create + " " + run + " " + destroy);
1200
1201 final VolumeRecord rec = findRecordForPath(path);
1202 if (rec != null) {
1203 rec.lastBenchMillis = System.currentTimeMillis();
1204 writeSettingsLocked();
1205 }
1206
1207 break;
1208 }
1209 case VoldResponseCode.TRIM_RESULT: {
1210 if (cooked.length != 4) break;
1211 final String path = cooked[1];
1212 final long bytes = Long.parseLong(cooked[2]);
1213 final long time = Long.parseLong(cooked[3]);
1214
1215 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
1216 dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path)
1217 + " " + bytes + " " + time);
1218
1219 final VolumeRecord rec = findRecordForPath(path);
1220 if (rec != null) {
1221 rec.lastTrimMillis = System.currentTimeMillis();
1222 writeSettingsLocked();
1223 }
1224
Jeff Sharkey9756d752015-05-14 21:07:42 -07001225 break;
1226 }
1227
Jeff Sharkey48877892015-03-18 11:27:19 -07001228 default: {
1229 Slog.d(TAG, "Unhandled vold event " + code);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001230 }
San Mehat4270e1e2010-01-29 05:32:19 -08001231 }
1232
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001233 return true;
San Mehat4270e1e2010-01-29 05:32:19 -08001234 }
1235
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001236 private void onDiskScannedLocked(DiskInfo disk) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001237 int volumeCount = 0;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001238 for (int i = 0; i < mVolumes.size(); i++) {
1239 final VolumeInfo vol = mVolumes.valueAt(i);
1240 if (Objects.equals(disk.id, vol.getDiskId())) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001241 volumeCount++;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001242 }
1243 }
1244
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001245 final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
Jeff Sharkey7732e1e2016-03-30 17:14:23 -06001246 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1247 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001248 intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
1249 intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001250 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001251
1252 final CountDownLatch latch = mDiskScanLatches.remove(disk.id);
1253 if (latch != null) {
1254 latch.countDown();
1255 }
1256
Jeff Sharkeyf5a6bd72015-05-19 14:42:38 -07001257 disk.volumeCount = volumeCount;
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001258 mCallbacks.notifyDiskScanned(disk, volumeCount);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001259 }
1260
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001261 private void onVolumeCreatedLocked(VolumeInfo vol) {
Jeff Sharkey6855c482016-03-31 14:34:38 -06001262 if (mPms.isOnlyCoreApps()) {
1263 Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId());
1264 return;
1265 }
1266
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001267 if (vol.type == VolumeInfo.TYPE_EMULATED) {
1268 final StorageManager storage = mContext.getSystemService(StorageManager.class);
1269 final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
1270
1271 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
1272 && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
1273 Slog.v(TAG, "Found primary storage at " + vol);
1274 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1275 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1276 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1277
1278 } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
1279 Slog.v(TAG, "Found primary storage at " + vol);
1280 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1281 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1282 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1283 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001284
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001285 } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001286 // TODO: only look at first public partition
1287 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1288 && vol.disk.isDefaultPrimary()) {
1289 Slog.v(TAG, "Found primary storage at " + vol);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001290 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1291 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
San Mehat4270e1e2010-01-29 05:32:19 -08001292 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001293
1294 // Adoptable public disks are visible to apps, since they meet
1295 // public API requirement of being in a stable location.
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001296 if (vol.disk.isAdoptable()) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001297 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1298 }
1299
Jeff Sharkeyab15c392016-05-05 11:45:01 -06001300 vol.mountUserId = mCurrentUserId;
Jeff Sharkey48877892015-03-18 11:27:19 -07001301 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001302
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001303 } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1304 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1305
San Mehat4270e1e2010-01-29 05:32:19 -08001306 } else {
Jeff Sharkey48877892015-03-18 11:27:19 -07001307 Slog.d(TAG, "Skipping automatic mounting of " + vol);
San Mehat4270e1e2010-01-29 05:32:19 -08001308 }
1309 }
1310
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001311 private boolean isBroadcastWorthy(VolumeInfo vol) {
1312 switch (vol.getType()) {
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001313 case VolumeInfo.TYPE_PRIVATE:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001314 case VolumeInfo.TYPE_PUBLIC:
1315 case VolumeInfo.TYPE_EMULATED:
1316 break;
1317 default:
1318 return false;
1319 }
1320
1321 switch (vol.getState()) {
1322 case VolumeInfo.STATE_MOUNTED:
1323 case VolumeInfo.STATE_MOUNTED_READ_ONLY:
1324 case VolumeInfo.STATE_EJECTING:
1325 case VolumeInfo.STATE_UNMOUNTED:
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001326 case VolumeInfo.STATE_UNMOUNTABLE:
Tony Mantlerf0d71052015-06-24 11:45:25 -07001327 case VolumeInfo.STATE_BAD_REMOVAL:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001328 break;
1329 default:
1330 return false;
1331 }
1332
1333 return true;
1334 }
1335
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001336 private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001337 // Remember that we saw this volume so we're ready to accept user
1338 // metadata, or so we can annoy them when a private volume is ejected
1339 if (vol.isMountedReadable() && !TextUtils.isEmpty(vol.fsUuid)) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001340 VolumeRecord rec = mRecords.get(vol.fsUuid);
1341 if (rec == null) {
1342 rec = new VolumeRecord(vol.type, vol.fsUuid);
1343 rec.partGuid = vol.partGuid;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001344 rec.createdMillis = System.currentTimeMillis();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001345 if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1346 rec.nickname = vol.disk.getDescription();
1347 }
1348 mRecords.put(rec.fsUuid, rec);
1349 writeSettingsLocked();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001350 } else {
1351 // Handle upgrade case where we didn't store partition GUID
1352 if (TextUtils.isEmpty(rec.partGuid)) {
1353 rec.partGuid = vol.partGuid;
1354 writeSettingsLocked();
1355 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001356 }
1357 }
1358
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001359 mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
1360
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001361 // Do not broadcast before boot has completed to avoid launching the
1362 // processes that receive the intent unnecessarily.
1363 if (mBootCompleted && isBroadcastWorthy(vol)) {
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001364 final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001365 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
1366 intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
Tony Mantlerf0d71052015-06-24 11:45:25 -07001367 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
Jeff Sharkey7732e1e2016-03-30 17:14:23 -06001368 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1369 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001370 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001371 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001372
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001373 final String oldStateEnv = VolumeInfo.getEnvironmentForState(oldState);
1374 final String newStateEnv = VolumeInfo.getEnvironmentForState(newState);
Emily Bernier92aa5a22014-07-07 10:11:48 -04001375
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001376 if (!Objects.equals(oldStateEnv, newStateEnv)) {
1377 // Kick state changed event towards all started users. Any users
1378 // started after this point will trigger additional
1379 // user-specific broadcasts.
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001380 for (int userId : mSystemUnlockedUsers) {
Jeff Sharkey46349872015-07-28 10:49:47 -07001381 if (vol.isVisibleForRead(userId)) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001382 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001383 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey48877892015-03-18 11:27:19 -07001384
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001385 mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
1386 newStateEnv);
San Mehat4270e1e2010-01-29 05:32:19 -08001387 }
1388 }
1389 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001390
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001391 if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.state == VolumeInfo.STATE_EJECTING) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001392 // TODO: this should eventually be handled by new ObbVolume state changes
1393 /*
1394 * Some OBBs might have been unmounted when this volume was
1395 * unmounted, so send a message to the handler to let it know to
1396 * remove those from the list of mounted OBBS.
1397 */
1398 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
1399 OBB_FLUSH_MOUNT_STATE, vol.path));
1400 }
San Mehat4270e1e2010-01-29 05:32:19 -08001401 }
1402
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001403 private void onMoveStatusLocked(int status) {
1404 if (mMoveCallback == null) {
1405 Slog.w(TAG, "Odd, status but no move requested");
1406 return;
1407 }
1408
1409 // TODO: estimate remaining time
1410 try {
Jeff Sharkey50a05452015-04-29 11:24:52 -07001411 mMoveCallback.onStatusChanged(-1, status, -1);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001412 } catch (RemoteException ignored) {
1413 }
1414
1415 // We've finished copying and we're about to clean up old data, so
1416 // remember that move was successful if we get rebooted
1417 if (status == MOVE_STATUS_COPY_FINISHED) {
1418 Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
1419
1420 mPrimaryStorageUuid = mMoveTargetUuid;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001421 writeSettingsLocked();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001422 }
1423
1424 if (PackageManager.isMoveStatusFinished(status)) {
1425 Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status);
1426
1427 mMoveCallback = null;
1428 mMoveTargetUuid = null;
1429 }
1430 }
1431
Jeff Sharkey48877892015-03-18 11:27:19 -07001432 private void enforcePermission(String perm) {
1433 mContext.enforceCallingOrSelfPermission(perm, perm);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001434 }
1435
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001436 /**
1437 * Decide if volume is mountable per device policies.
1438 */
1439 private boolean isMountDisallowed(VolumeInfo vol) {
1440 if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
1441 final UserManager userManager = mContext.getSystemService(UserManager.class);
1442 return userManager.hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
1443 Binder.getCallingUserHandle());
1444 } else {
1445 return false;
Emily Bernier92aa5a22014-07-07 10:11:48 -04001446 }
1447 }
1448
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001449 private void enforceAdminUser() {
1450 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1451 final int callingUserId = UserHandle.getCallingUserId();
1452 boolean isAdmin;
1453 long token = Binder.clearCallingIdentity();
1454 try {
1455 isAdmin = um.getUserInfo(callingUserId).isAdmin();
1456 } finally {
1457 Binder.restoreCallingIdentity(token);
1458 }
1459 if (!isAdmin) {
1460 throw new SecurityException("Only admin users can adopt sd cards");
1461 }
1462 }
1463
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001464 /**
San Mehat207e5382010-02-04 20:46:54 -08001465 * Constructs a new MountService instance
1466 *
1467 * @param context Binder context for this service
1468 */
1469 public MountService(Context context) {
Christopher Tated417d622013-08-19 16:14:25 -07001470 sSelf = this;
1471
San Mehat207e5382010-02-04 20:46:54 -08001472 mContext = context;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001473 mCallbacks = new Callbacks(FgThread.get().getLooper());
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001474 mLockPatternUtils = new LockPatternUtils(mContext);
San Mehat207e5382010-02-04 20:46:54 -08001475
San Mehat207e5382010-02-04 20:46:54 -08001476 // XXX: This will go away soon in favor of IMountServiceObserver
1477 mPms = (PackageManagerService) ServiceManager.getService("package");
1478
Dianne Hackbornefa92b22013-05-03 14:11:43 -07001479 HandlerThread hthread = new HandlerThread(TAG);
1480 hthread.start();
1481 mHandler = new MountServiceHandler(hthread.getLooper());
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001482
Kenny Roota02b8b02010-08-05 16:14:17 -07001483 // Add OBB Action Handler to MountService thread.
Dianne Hackborn8d044e82013-04-30 17:24:15 -07001484 mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
Kenny Roota02b8b02010-08-05 16:14:17 -07001485
Christopher Tate7265abe2014-11-21 13:54:45 -08001486 // Initialize the last-fstrim tracking if necessary
1487 File dataDir = Environment.getDataDirectory();
1488 File systemDir = new File(dataDir, "system");
1489 mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
1490 if (!mLastMaintenanceFile.exists()) {
1491 // Not setting mLastMaintenance here means that we will force an
1492 // fstrim during reboot following the OTA that installs this code.
1493 try {
1494 (new FileOutputStream(mLastMaintenanceFile)).close();
1495 } catch (IOException e) {
1496 Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
1497 }
1498 } else {
1499 mLastMaintenance = mLastMaintenanceFile.lastModified();
1500 }
1501
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001502 mSettingsFile = new AtomicFile(
Jeff Sharkey8212ae02016-02-10 14:46:43 -07001503 new File(Environment.getDataSystemDirectory(), "storage.xml"));
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001504
1505 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001506 readSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001507 }
1508
Svet Ganov6ee871e2015-07-10 14:29:33 -07001509 LocalServices.addService(MountServiceInternal.class, mMountServiceInternal);
1510
Marco Nelissenc34ebce2010-02-18 13:39:41 -08001511 /*
Kenny Root305bcbf2010-09-03 07:56:38 -07001512 * Create the connection to vold with a maximum queue of twice the
1513 * amount of containers we'd ever expect to have. This keeps an
1514 * "asec list" from blocking a thread repeatedly.
1515 */
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001516
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001517 mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
1518 null);
Jeff Sharkey48877892015-03-18 11:27:19 -07001519 mConnector.setDebug(true);
Jeff Sharkey8948c012015-11-03 12:33:54 -08001520 mConnector.setWarnIfHeld(mLock);
Jeff Sharkeycd575992016-03-29 14:12:49 -06001521 mConnectorThread = new Thread(mConnector, VOLD_TAG);
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07001522
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001523 // Reuse parameters from first connector since they are tested and safe
1524 mCryptConnector = new NativeDaemonConnector(this, "cryptd",
1525 MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
1526 mCryptConnector.setDebug(true);
Jeff Sharkeycd575992016-03-29 14:12:49 -06001527 mCryptConnectorThread = new Thread(mCryptConnector, CRYPTD_TAG);
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001528
Jeff Sharkeybcd262d2015-06-10 09:41:17 -07001529 final IntentFilter userFilter = new IntentFilter();
1530 userFilter.addAction(Intent.ACTION_USER_ADDED);
1531 userFilter.addAction(Intent.ACTION_USER_REMOVED);
1532 mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
1533
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001534 synchronized (mLock) {
1535 addInternalVolumeLocked();
1536 }
Amith Yamasania7892482015-08-07 11:09:05 -07001537
Kenny Root07714d42011-08-17 17:49:28 -07001538 // Add ourself to the Watchdog monitors if enabled.
1539 if (WATCHDOG_ENABLE) {
1540 Watchdog.getInstance().addMonitor(this);
1541 }
San Mehat207e5382010-02-04 20:46:54 -08001542 }
1543
Jeff Sharkeycd575992016-03-29 14:12:49 -06001544 private void start() {
1545 mConnectorThread.start();
1546 mCryptConnectorThread.start();
1547 }
1548
Jeff Sharkey56e62932015-03-21 20:41:00 -07001549 private void systemReady() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001550 mSystemReady = true;
1551 mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
1552 }
1553
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001554 private void bootCompleted() {
1555 mBootCompleted = true;
1556 }
1557
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001558 private String getDefaultPrimaryStorageUuid() {
1559 if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) {
1560 return StorageManager.UUID_PRIMARY_PHYSICAL;
1561 } else {
1562 return StorageManager.UUID_PRIVATE_INTERNAL;
1563 }
1564 }
1565
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001566 private void readSettingsLocked() {
1567 mRecords.clear();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001568 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001569 mForceAdoptable = false;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001570
1571 FileInputStream fis = null;
1572 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001573 fis = mSettingsFile.openRead();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001574 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001575 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001576
1577 int type;
1578 while ((type = in.next()) != END_DOCUMENT) {
1579 if (type == START_TAG) {
1580 final String tag = in.getName();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001581 if (TAG_VOLUMES.equals(tag)) {
1582 final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001583 final boolean primaryPhysical = SystemProperties.getBoolean(
1584 StorageManager.PROP_PRIMARY_PHYSICAL, false);
1585 final boolean validAttr = (version >= VERSION_FIX_PRIMARY)
1586 || (version >= VERSION_ADD_PRIMARY && !primaryPhysical);
1587 if (validAttr) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001588 mPrimaryStorageUuid = readStringAttribute(in,
1589 ATTR_PRIMARY_STORAGE_UUID);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001590 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001591 mForceAdoptable = readBooleanAttribute(in, ATTR_FORCE_ADOPTABLE, false);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001592
1593 } else if (TAG_VOLUME.equals(tag)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001594 final VolumeRecord rec = readVolumeRecord(in);
1595 mRecords.put(rec.fsUuid, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001596 }
1597 }
1598 }
1599 } catch (FileNotFoundException e) {
1600 // Missing metadata is okay, probably first boot
1601 } catch (IOException e) {
1602 Slog.wtf(TAG, "Failed reading metadata", e);
1603 } catch (XmlPullParserException e) {
1604 Slog.wtf(TAG, "Failed reading metadata", e);
1605 } finally {
1606 IoUtils.closeQuietly(fis);
1607 }
1608 }
1609
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001610 private void writeSettingsLocked() {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001611 FileOutputStream fos = null;
1612 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001613 fos = mSettingsFile.startWrite();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001614
1615 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001616 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001617 out.startDocument(null, true);
1618 out.startTag(null, TAG_VOLUMES);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001619 writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001620 writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001621 writeBooleanAttribute(out, ATTR_FORCE_ADOPTABLE, mForceAdoptable);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001622 final int size = mRecords.size();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001623 for (int i = 0; i < size; i++) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001624 final VolumeRecord rec = mRecords.valueAt(i);
1625 writeVolumeRecord(out, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001626 }
1627 out.endTag(null, TAG_VOLUMES);
1628 out.endDocument();
1629
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001630 mSettingsFile.finishWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001631 } catch (IOException e) {
1632 if (fos != null) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001633 mSettingsFile.failWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001634 }
1635 }
1636 }
1637
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001638 public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
1639 final int type = readIntAttribute(in, ATTR_TYPE);
1640 final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
1641 final VolumeRecord meta = new VolumeRecord(type, fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001642 meta.partGuid = readStringAttribute(in, ATTR_PART_GUID);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001643 meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
1644 meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001645 meta.createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
1646 meta.lastTrimMillis = readLongAttribute(in, ATTR_LAST_TRIM_MILLIS);
1647 meta.lastBenchMillis = readLongAttribute(in, ATTR_LAST_BENCH_MILLIS);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001648 return meta;
1649 }
1650
1651 public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
1652 out.startTag(null, TAG_VOLUME);
1653 writeIntAttribute(out, ATTR_TYPE, rec.type);
1654 writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001655 writeStringAttribute(out, ATTR_PART_GUID, rec.partGuid);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001656 writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
1657 writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001658 writeLongAttribute(out, ATTR_CREATED_MILLIS, rec.createdMillis);
1659 writeLongAttribute(out, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
1660 writeLongAttribute(out, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001661 out.endTag(null, TAG_VOLUME);
1662 }
1663
San Mehat207e5382010-02-04 20:46:54 -08001664 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001665 * Exposed API calls below here
1666 */
1667
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001668 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001669 public void registerListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001670 mCallbacks.register(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001671 }
1672
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001673 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001674 public void unregisterListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001675 mCallbacks.unregister(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001676 }
1677
Jeff Sharkey48877892015-03-18 11:27:19 -07001678 @Override
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -08001679 public void shutdown(final IMountShutdownObserver observer) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001680 enforcePermission(android.Manifest.permission.SHUTDOWN);
San Mehat4270e1e2010-01-29 05:32:19 -08001681
San Mehata5078592010-03-25 09:36:54 -07001682 Slog.i(TAG, "Shutting down");
Jeff Sharkey48877892015-03-18 11:27:19 -07001683 mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001684 }
1685
Jeff Sharkey48877892015-03-18 11:27:19 -07001686 @Override
San Mehatb1043402010-02-05 08:26:50 -08001687 public boolean isUsbMassStorageConnected() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001688 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001689 }
1690
Jeff Sharkey48877892015-03-18 11:27:19 -07001691 @Override
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -08001692 public void setUsbMassStorageEnabled(boolean enable) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001693 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001694 }
1695
Jeff Sharkey48877892015-03-18 11:27:19 -07001696 @Override
San Mehatb1043402010-02-05 08:26:50 -08001697 public boolean isUsbMassStorageEnabled() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001698 throw new UnsupportedOperationException();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 }
Jason parks9ed98bc2011-01-17 09:58:35 -06001700
Jeff Sharkey48877892015-03-18 11:27:19 -07001701 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001702 public String getVolumeState(String mountPoint) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001703 throw new UnsupportedOperationException();
San Mehat7fd0fee2009-12-17 07:12:23 -08001704 }
1705
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001706 @Override
Kenny Roote1ff2142010-10-12 11:20:01 -07001707 public boolean isExternalStorageEmulated() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001708 throw new UnsupportedOperationException();
Kenny Roote1ff2142010-10-12 11:20:01 -07001709 }
1710
Jeff Sharkey48877892015-03-18 11:27:19 -07001711 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001712 public int mountVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001713 mount(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001714 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715 }
1716
Jeff Sharkey48877892015-03-18 11:27:19 -07001717 @Override
Ben Komalo13c71972011-09-07 16:35:56 -07001718 public void unmountVolume(String path, boolean force, boolean removeEncryption) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001719 unmount(findVolumeIdForPathOrThrow(path));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720 }
1721
Jeff Sharkey48877892015-03-18 11:27:19 -07001722 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001723 public int formatVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001724 format(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001725 return 0;
1726 }
1727
1728 @Override
1729 public void mount(String volId) {
1730 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1731 waitForReady();
1732
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001733 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001734 if (isMountDisallowed(vol)) {
1735 throw new SecurityException("Mounting " + volId + " restricted by policy");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001736 }
1737 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001738 mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001739 } catch (NativeDaemonConnectorException e) {
1740 throw e.rethrowAsParcelableException();
1741 }
1742 }
1743
1744 @Override
1745 public void unmount(String volId) {
1746 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1747 waitForReady();
1748
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001749 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001750
1751 // TODO: expand PMS to know about multiple volumes
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001752 if (vol.isPrimaryPhysical()) {
1753 final long ident = Binder.clearCallingIdentity();
1754 try {
1755 synchronized (mUnmountLock) {
1756 mUnmountSignal = new CountDownLatch(1);
1757 mPms.updateExternalMediaStatus(false, true);
1758 waitForLatch(mUnmountSignal, "mUnmountSignal");
1759 mUnmountSignal = null;
1760 }
1761 } finally {
1762 Binder.restoreCallingIdentity(ident);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001763 }
1764 }
1765
1766 try {
1767 mConnector.execute("volume", "unmount", vol.id);
1768 } catch (NativeDaemonConnectorException e) {
1769 throw e.rethrowAsParcelableException();
1770 }
1771 }
1772
1773 @Override
1774 public void format(String volId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001775 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -08001776 waitForReady();
San Mehat5b77dab2010-01-26 13:28:50 -08001777
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001778 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001779 try {
Jeff Sharkey4e83cc92015-05-27 14:38:39 -07001780 mConnector.execute("volume", "format", vol.id, "auto");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001781 } catch (NativeDaemonConnectorException e) {
1782 throw e.rethrowAsParcelableException();
Jeff Sharkey48877892015-03-18 11:27:19 -07001783 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001784 }
1785
1786 @Override
Jeff Sharkey9756d752015-05-14 21:07:42 -07001787 public long benchmark(String volId) {
1788 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1789 waitForReady();
1790
1791 try {
Jeff Sharkey14cbe522015-07-08 14:06:37 -07001792 // TODO: make benchmark async so we don't block other commands
1793 final NativeDaemonEvent res = mConnector.execute(3 * DateUtils.MINUTE_IN_MILLIS,
1794 "volume", "benchmark", volId);
Jeff Sharkey9756d752015-05-14 21:07:42 -07001795 return Long.parseLong(res.getMessage());
Todd Kennedy8101ee62015-06-23 13:35:28 -07001796 } catch (NativeDaemonTimeoutException e) {
1797 return Long.MAX_VALUE;
Jeff Sharkey9756d752015-05-14 21:07:42 -07001798 } catch (NativeDaemonConnectorException e) {
1799 throw e.rethrowAsParcelableException();
1800 }
1801 }
1802
1803 @Override
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001804 public void partitionPublic(String diskId) {
1805 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1806 waitForReady();
1807
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001808 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001809 try {
1810 mConnector.execute("volume", "partition", diskId, "public");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001811 waitForLatch(latch, "partitionPublic", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001812 } catch (NativeDaemonConnectorException e) {
1813 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001814 } catch (TimeoutException e) {
1815 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001816 }
1817 }
1818
1819 @Override
1820 public void partitionPrivate(String diskId) {
1821 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001822 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001823 waitForReady();
1824
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001825 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001826 try {
1827 mConnector.execute("volume", "partition", diskId, "private");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001828 waitForLatch(latch, "partitionPrivate", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001829 } catch (NativeDaemonConnectorException e) {
1830 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001831 } catch (TimeoutException e) {
1832 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001833 }
1834 }
1835
1836 @Override
1837 public void partitionMixed(String diskId, int ratio) {
1838 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001839 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001840 waitForReady();
1841
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001842 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001843 try {
1844 mConnector.execute("volume", "partition", diskId, "mixed", ratio);
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001845 waitForLatch(latch, "partitionMixed", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001846 } catch (NativeDaemonConnectorException e) {
1847 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001848 } catch (TimeoutException e) {
1849 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001850 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001851 }
1852
Jeff Sharkey48877892015-03-18 11:27:19 -07001853 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001854 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001855 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1856 waitForReady();
1857
Jeff Sharkey50a05452015-04-29 11:24:52 -07001858 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001859 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001860 final VolumeRecord rec = mRecords.get(fsUuid);
1861 rec.nickname = nickname;
Jeff Sharkey50a05452015-04-29 11:24:52 -07001862 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001863 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001864 }
1865 }
1866
1867 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001868 public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001869 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1870 waitForReady();
1871
Jeff Sharkey50a05452015-04-29 11:24:52 -07001872 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001873 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001874 final VolumeRecord rec = mRecords.get(fsUuid);
1875 rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001876 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001877 writeSettingsLocked();
1878 }
1879 }
1880
1881 @Override
1882 public void forgetVolume(String fsUuid) {
1883 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1884 waitForReady();
1885
Jeff Sharkey50a05452015-04-29 11:24:52 -07001886 Preconditions.checkNotNull(fsUuid);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001887
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001888 synchronized (mLock) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001889 final VolumeRecord rec = mRecords.remove(fsUuid);
1890 if (rec != null && !TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001891 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001892 }
1893 mCallbacks.notifyVolumeForgotten(fsUuid);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001894
1895 // If this had been primary storage, revert back to internal and
1896 // reset vold so we bind into new volume into place.
1897 if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001898 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001899 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001900 }
1901
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001902 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001903 }
1904 }
1905
Jeff Sharkey7d2af542015-05-12 15:27:15 -07001906 @Override
1907 public void forgetAllVolumes() {
1908 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1909 waitForReady();
1910
Jeff Sharkey50a05452015-04-29 11:24:52 -07001911 synchronized (mLock) {
1912 for (int i = 0; i < mRecords.size(); i++) {
1913 final String fsUuid = mRecords.keyAt(i);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001914 final VolumeRecord rec = mRecords.valueAt(i);
1915 if (!TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001916 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001917 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001918 mCallbacks.notifyVolumeForgotten(fsUuid);
1919 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001920 mRecords.clear();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001921
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001922 if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)) {
1923 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
1924 }
1925
1926 writeSettingsLocked();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001927 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001928 }
1929 }
1930
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001931 private void forgetPartition(String partGuid) {
1932 try {
1933 mConnector.execute("volume", "forget_partition", partGuid);
1934 } catch (NativeDaemonConnectorException e) {
1935 Slog.w(TAG, "Failed to forget key for " + partGuid + ": " + e);
1936 }
1937 }
1938
Svet Ganov6ee871e2015-07-10 14:29:33 -07001939 private void remountUidExternalStorage(int uid, int mode) {
Jeff Sharkey9527b222015-06-24 15:24:48 -07001940 waitForReady();
1941
Svet Ganov6ee871e2015-07-10 14:29:33 -07001942 String modeName = "none";
1943 switch (mode) {
1944 case Zygote.MOUNT_EXTERNAL_DEFAULT: {
1945 modeName = "default";
1946 } break;
1947
1948 case Zygote.MOUNT_EXTERNAL_READ: {
1949 modeName = "read";
1950 } break;
1951
1952 case Zygote.MOUNT_EXTERNAL_WRITE: {
1953 modeName = "write";
1954 } break;
Jeff Sharkey9527b222015-06-24 15:24:48 -07001955 }
1956
1957 try {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001958 mConnector.execute("volume", "remount_uid", uid, modeName);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001959 } catch (NativeDaemonConnectorException e) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001960 Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001961 }
1962 }
1963
1964 @Override
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001965 public void setDebugFlags(int flags, int mask) {
1966 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1967 waitForReady();
1968
Jeff Sharkeyba512352015-11-12 20:17:45 -08001969 if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
Paul Lawrence20be5d62016-02-26 13:51:17 -08001970 if (StorageManager.isFileEncryptedNativeOnly()) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001971 throw new IllegalStateException(
1972 "Emulation not available on device with native FBE");
1973 }
Jeff Sharkey5a785162016-03-21 13:02:06 -06001974 if (mLockPatternUtils.isCredentialRequiredToDecrypt(false)) {
1975 throw new IllegalStateException(
1976 "Emulation requires disabling 'Secure start-up' in Settings > Security");
1977 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001978
Jeff Sharkey1176e512016-02-29 17:01:26 -07001979 final long token = Binder.clearCallingIdentity();
1980 try {
1981 final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
1982 SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001983
Jeff Sharkey1176e512016-02-29 17:01:26 -07001984 // Perform hard reboot to kick policy into place
1985 mContext.getSystemService(PowerManager.class).reboot(null);
1986 } finally {
1987 Binder.restoreCallingIdentity(token);
1988 }
Jeff Sharkeyba512352015-11-12 20:17:45 -08001989 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001990
Jeff Sharkeyba512352015-11-12 20:17:45 -08001991 if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
Jeff Sharkey6ed74182016-08-23 13:53:53 -06001992 if (StorageManager.isFileEncryptedNativeOnly()) {
1993 throw new IllegalStateException(
1994 "Adoptable storage not available on device with native FBE");
1995 }
1996
Jeff Sharkeyba512352015-11-12 20:17:45 -08001997 synchronized (mLock) {
1998 mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
1999
2000 writeSettingsLocked();
2001 mHandler.obtainMessage(H_RESET).sendToTarget();
2002 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002003 }
Jeff Sharkey33dd1562016-04-07 11:05:33 -06002004
2005 if ((mask & (StorageManager.DEBUG_SDCARDFS_FORCE_ON
2006 | StorageManager.DEBUG_SDCARDFS_FORCE_OFF)) != 0) {
2007 final String value;
2008 if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_ON) != 0) {
2009 value = "force_on";
2010 } else if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_OFF) != 0) {
2011 value = "force_off";
2012 } else {
2013 value = "";
2014 }
2015
2016 final long token = Binder.clearCallingIdentity();
2017 try {
2018 SystemProperties.set(StorageManager.PROP_SDCARDFS, value);
2019
2020 // Reset storage to kick new setting into place
2021 mHandler.obtainMessage(H_RESET).sendToTarget();
2022 } finally {
2023 Binder.restoreCallingIdentity(token);
2024 }
2025 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002026 }
2027
2028 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002029 public String getPrimaryStorageUuid() {
2030 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2031 waitForReady();
2032
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002033 synchronized (mLock) {
2034 return mPrimaryStorageUuid;
2035 }
2036 }
2037
2038 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002039 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
2040 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2041 waitForReady();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002042
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002043 final VolumeInfo from;
2044 final VolumeInfo to;
2045
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002046 synchronized (mLock) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002047 if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) {
2048 throw new IllegalArgumentException("Primary storage already at " + volumeUuid);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002049 }
2050
2051 if (mMoveCallback != null) {
2052 throw new IllegalStateException("Move already in progress");
2053 }
2054 mMoveCallback = callback;
2055 mMoveTargetUuid = volumeUuid;
2056
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002057 // When moving to/from primary physical volume, we probably just nuked
2058 // the current storage location, so we have nothing to move.
2059 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
2060 || Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
2061 Slog.d(TAG, "Skipping move to/from primary physical");
2062 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
2063 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08002064 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002065 return;
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002066
2067 } else {
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002068 from = findStorageForUuid(mPrimaryStorageUuid);
2069 to = findStorageForUuid(volumeUuid);
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07002070
2071 if (from == null) {
2072 Slog.w(TAG, "Failing move due to missing from volume " + mPrimaryStorageUuid);
2073 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2074 return;
2075 } else if (to == null) {
2076 Slog.w(TAG, "Failing move due to missing to volume " + volumeUuid);
2077 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2078 return;
2079 }
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002080 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002081 }
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002082
2083 try {
2084 mConnector.execute("volume", "move_storage", from.id, to.id);
2085 } catch (NativeDaemonConnectorException e) {
2086 throw e.rethrowAsParcelableException();
2087 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002088 }
2089
2090 @Override
Mike Lockwoodecedfdc2011-06-08 15:11:59 -07002091 public int[] getStorageUsers(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002092 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehatc1b4ce92010-02-16 17:13:03 -08002093 waitForReady();
2094 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002095 final String[] r = NativeDaemonEvent.filterMessageList(
2096 mConnector.executeForList("storage", "users", path),
2097 VoldResponseCode.StorageUsersListResult);
2098
San Mehatc1b4ce92010-02-16 17:13:03 -08002099 // FMT: <pid> <process name>
2100 int[] data = new int[r.length];
2101 for (int i = 0; i < r.length; i++) {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002102 String[] tok = r[i].split(" ");
San Mehatc1b4ce92010-02-16 17:13:03 -08002103 try {
2104 data[i] = Integer.parseInt(tok[0]);
2105 } catch (NumberFormatException nfe) {
San Mehata5078592010-03-25 09:36:54 -07002106 Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
San Mehatc1b4ce92010-02-16 17:13:03 -08002107 return new int[0];
2108 }
2109 }
2110 return data;
2111 } catch (NativeDaemonConnectorException e) {
San Mehata5078592010-03-25 09:36:54 -07002112 Slog.e(TAG, "Failed to retrieve storage users list", e);
San Mehatc1b4ce92010-02-16 17:13:03 -08002113 return new int[0];
2114 }
2115 }
2116
San Mehatb1043402010-02-05 08:26:50 -08002117 private void warnOnNotMounted() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002118 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002119 for (int i = 0; i < mVolumes.size(); i++) {
2120 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07002121 if (vol.isPrimary() && vol.isMountedWritable()) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002122 // Cool beans, we have a mounted primary volume
2123 return;
2124 }
Jeff Sharkey32ee8312012-09-30 13:21:31 -07002125 }
San Mehatb1043402010-02-05 08:26:50 -08002126 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002127
2128 Slog.w(TAG, "No primary storage mounted!");
San Mehatb1043402010-02-05 08:26:50 -08002129 }
2130
San Mehat4270e1e2010-01-29 05:32:19 -08002131 public String[] getSecureContainerList() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002132 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002133 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002134 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002135
San Mehat4270e1e2010-01-29 05:32:19 -08002136 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002137 return NativeDaemonEvent.filterMessageList(
2138 mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
San Mehat4270e1e2010-01-29 05:32:19 -08002139 } catch (NativeDaemonConnectorException e) {
2140 return new String[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002141 }
2142 }
San Mehat36972292010-01-06 11:06:32 -08002143
Kenny Root6dceb882012-04-12 14:23:49 -07002144 public int createSecureContainer(String id, int sizeMb, String fstype, String key,
2145 int ownerUid, boolean external) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002146 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehat207e5382010-02-04 20:46:54 -08002147 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002148 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002149
San Mehatb1043402010-02-05 08:26:50 -08002150 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002151 try {
Jeff Sharkey56cd6462013-06-07 15:09:15 -07002152 mConnector.execute("asec", "create", id, sizeMb, fstype, new SensitiveArg(key),
2153 ownerUid, external ? "1" : "0");
San Mehat4270e1e2010-01-29 05:32:19 -08002154 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002155 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002156 }
San Mehata181b212010-02-11 06:50:20 -08002157
2158 if (rc == StorageResultCode.OperationSucceeded) {
2159 synchronized (mAsecMountSet) {
2160 mAsecMountSet.add(id);
2161 }
2162 }
San Mehat4270e1e2010-01-29 05:32:19 -08002163 return rc;
San Mehat36972292010-01-06 11:06:32 -08002164 }
2165
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002166 @Override
2167 public int resizeSecureContainer(String id, int sizeMb, String key) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002168 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002169 waitForReady();
2170 warnOnNotMounted();
2171
2172 int rc = StorageResultCode.OperationSucceeded;
2173 try {
2174 mConnector.execute("asec", "resize", id, sizeMb, new SensitiveArg(key));
2175 } catch (NativeDaemonConnectorException e) {
2176 rc = StorageResultCode.OperationFailedInternalError;
2177 }
2178 return rc;
2179 }
2180
San Mehat4270e1e2010-01-29 05:32:19 -08002181 public int finalizeSecureContainer(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002182 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehatb1043402010-02-05 08:26:50 -08002183 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002184
San Mehatb1043402010-02-05 08:26:50 -08002185 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002186 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002187 mConnector.execute("asec", "finalize", id);
San Mehata181b212010-02-11 06:50:20 -08002188 /*
2189 * Finalization does a remount, so no need
2190 * to update mAsecMountSet
2191 */
San Mehat4270e1e2010-01-29 05:32:19 -08002192 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002193 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002194 }
San Mehat4270e1e2010-01-29 05:32:19 -08002195 return rc;
San Mehat36972292010-01-06 11:06:32 -08002196 }
2197
Kenny Root6dceb882012-04-12 14:23:49 -07002198 public int fixPermissionsSecureContainer(String id, int gid, String filename) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002199 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Kenny Root6dceb882012-04-12 14:23:49 -07002200 warnOnNotMounted();
2201
2202 int rc = StorageResultCode.OperationSucceeded;
2203 try {
2204 mConnector.execute("asec", "fixperms", id, gid, filename);
2205 /*
2206 * Fix permissions does a remount, so no need to update
2207 * mAsecMountSet
2208 */
2209 } catch (NativeDaemonConnectorException e) {
2210 rc = StorageResultCode.OperationFailedInternalError;
2211 }
2212 return rc;
2213 }
2214
San Mehatd9709982010-02-18 11:43:03 -08002215 public int destroySecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002216 enforcePermission(android.Manifest.permission.ASEC_DESTROY);
San Mehat207e5382010-02-04 20:46:54 -08002217 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002218 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002219
Kenny Rootaa485402010-09-14 14:49:41 -07002220 /*
2221 * Force a GC to make sure AssetManagers in other threads of the
2222 * system_server are cleaned up. We have to do this since AssetManager
2223 * instances are kept as a WeakReference and it's possible we have files
2224 * open on the external storage.
2225 */
2226 Runtime.getRuntime().gc();
2227
San Mehatb1043402010-02-05 08:26:50 -08002228 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002229 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002230 final Command cmd = new Command("asec", "destroy", id);
2231 if (force) {
2232 cmd.appendArg("force");
2233 }
2234 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002235 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002236 int code = e.getCode();
2237 if (code == VoldResponseCode.OpFailedStorageBusy) {
2238 rc = StorageResultCode.OperationFailedStorageBusy;
2239 } else {
2240 rc = StorageResultCode.OperationFailedInternalError;
2241 }
San Mehat02735bc2010-01-26 15:18:08 -08002242 }
San Mehata181b212010-02-11 06:50:20 -08002243
2244 if (rc == StorageResultCode.OperationSucceeded) {
2245 synchronized (mAsecMountSet) {
2246 if (mAsecMountSet.contains(id)) {
2247 mAsecMountSet.remove(id);
2248 }
2249 }
2250 }
2251
San Mehat4270e1e2010-01-29 05:32:19 -08002252 return rc;
San Mehat36972292010-01-06 11:06:32 -08002253 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002254
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002255 public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002256 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002257 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002258 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002259
San Mehata181b212010-02-11 06:50:20 -08002260 synchronized (mAsecMountSet) {
2261 if (mAsecMountSet.contains(id)) {
2262 return StorageResultCode.OperationFailedStorageMounted;
2263 }
2264 }
2265
San Mehatb1043402010-02-05 08:26:50 -08002266 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002267 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002268 mConnector.execute("asec", "mount", id, new SensitiveArg(key), ownerUid,
2269 readOnly ? "ro" : "rw");
San Mehat4270e1e2010-01-29 05:32:19 -08002270 } catch (NativeDaemonConnectorException e) {
Kenny Rootf0304622010-03-19 19:20:42 -07002271 int code = e.getCode();
2272 if (code != VoldResponseCode.OpFailedStorageBusy) {
2273 rc = StorageResultCode.OperationFailedInternalError;
2274 }
San Mehat02735bc2010-01-26 15:18:08 -08002275 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002276
2277 if (rc == StorageResultCode.OperationSucceeded) {
2278 synchronized (mAsecMountSet) {
2279 mAsecMountSet.add(id);
2280 }
2281 }
San Mehat4270e1e2010-01-29 05:32:19 -08002282 return rc;
San Mehat36972292010-01-06 11:06:32 -08002283 }
2284
San Mehatd9709982010-02-18 11:43:03 -08002285 public int unmountSecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002286 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002287 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002288 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002289
San Mehat6cdd9c02010-02-09 14:45:20 -08002290 synchronized (mAsecMountSet) {
2291 if (!mAsecMountSet.contains(id)) {
San Mehata181b212010-02-11 06:50:20 -08002292 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehat6cdd9c02010-02-09 14:45:20 -08002293 }
2294 }
2295
Kenny Rootaa485402010-09-14 14:49:41 -07002296 /*
2297 * Force a GC to make sure AssetManagers in other threads of the
2298 * system_server are cleaned up. We have to do this since AssetManager
2299 * instances are kept as a WeakReference and it's possible we have files
2300 * open on the external storage.
2301 */
2302 Runtime.getRuntime().gc();
2303
San Mehatb1043402010-02-05 08:26:50 -08002304 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002305 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002306 final Command cmd = new Command("asec", "unmount", id);
2307 if (force) {
2308 cmd.appendArg("force");
2309 }
2310 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002311 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002312 int code = e.getCode();
2313 if (code == VoldResponseCode.OpFailedStorageBusy) {
2314 rc = StorageResultCode.OperationFailedStorageBusy;
2315 } else {
2316 rc = StorageResultCode.OperationFailedInternalError;
2317 }
San Mehat02735bc2010-01-26 15:18:08 -08002318 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002319
2320 if (rc == StorageResultCode.OperationSucceeded) {
2321 synchronized (mAsecMountSet) {
2322 mAsecMountSet.remove(id);
2323 }
2324 }
San Mehat4270e1e2010-01-29 05:32:19 -08002325 return rc;
San Mehat9dba7092010-01-18 06:47:41 -08002326 }
2327
San Mehat6cdd9c02010-02-09 14:45:20 -08002328 public boolean isSecureContainerMounted(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002329 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat6cdd9c02010-02-09 14:45:20 -08002330 waitForReady();
2331 warnOnNotMounted();
2332
2333 synchronized (mAsecMountSet) {
2334 return mAsecMountSet.contains(id);
2335 }
2336 }
2337
San Mehat4270e1e2010-01-29 05:32:19 -08002338 public int renameSecureContainer(String oldId, String newId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002339 enforcePermission(android.Manifest.permission.ASEC_RENAME);
San Mehat207e5382010-02-04 20:46:54 -08002340 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002341 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002342
San Mehata181b212010-02-11 06:50:20 -08002343 synchronized (mAsecMountSet) {
San Mehat85451ee2010-02-24 08:54:18 -08002344 /*
Jason parks9ed98bc2011-01-17 09:58:35 -06002345 * Because a mounted container has active internal state which cannot be
San Mehat85451ee2010-02-24 08:54:18 -08002346 * changed while active, we must ensure both ids are not currently mounted.
2347 */
2348 if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
San Mehata181b212010-02-11 06:50:20 -08002349 return StorageResultCode.OperationFailedStorageMounted;
2350 }
2351 }
2352
San Mehatb1043402010-02-05 08:26:50 -08002353 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002354 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002355 mConnector.execute("asec", "rename", oldId, newId);
San Mehat4270e1e2010-01-29 05:32:19 -08002356 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002357 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002358 }
San Mehata181b212010-02-11 06:50:20 -08002359
San Mehat4270e1e2010-01-29 05:32:19 -08002360 return rc;
San Mehat45f61042010-01-23 08:12:43 -08002361 }
2362
San Mehat4270e1e2010-01-29 05:32:19 -08002363 public String getSecureContainerPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002364 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002365 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002366 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002367
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002368 final NativeDaemonEvent event;
San Mehat2d66cef2010-03-23 11:12:52 -07002369 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002370 event = mConnector.execute("asec", "path", id);
2371 event.checkCode(VoldResponseCode.AsecPathResult);
2372 return event.getMessage();
San Mehat2d66cef2010-03-23 11:12:52 -07002373 } catch (NativeDaemonConnectorException e) {
2374 int code = e.getCode();
2375 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Fredrik Helmera20c8ef2011-02-09 16:16:10 +01002376 Slog.i(TAG, String.format("Container '%s' not found", id));
2377 return null;
San Mehat22dd86e2010-01-12 12:21:18 -08002378 } else {
San Mehat2d66cef2010-03-23 11:12:52 -07002379 throw new IllegalStateException(String.format("Unexpected response code %d", code));
San Mehat22dd86e2010-01-12 12:21:18 -08002380 }
2381 }
San Mehat22dd86e2010-01-12 12:21:18 -08002382 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002383
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002384 public String getSecureContainerFilesystemPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002385 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002386 waitForReady();
2387 warnOnNotMounted();
2388
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002389 final NativeDaemonEvent event;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002390 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002391 event = mConnector.execute("asec", "fspath", id);
2392 event.checkCode(VoldResponseCode.AsecPathResult);
2393 return event.getMessage();
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002394 } catch (NativeDaemonConnectorException e) {
2395 int code = e.getCode();
2396 if (code == VoldResponseCode.OpFailedStorageNotFound) {
2397 Slog.i(TAG, String.format("Container '%s' not found", id));
2398 return null;
2399 } else {
2400 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2401 }
2402 }
2403 }
2404
Jeff Sharkey48877892015-03-18 11:27:19 -07002405 @Override
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002406 public void finishMediaUpdate() {
Jeff Sharkey9527b222015-06-24 15:24:48 -07002407 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
Rubin Xucd7a0142015-04-17 23:45:27 +01002408 throw new SecurityException("no permission to call finishMediaUpdate()");
2409 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002410 if (mUnmountSignal != null) {
2411 mUnmountSignal.countDown();
2412 } else {
2413 Slog.w(TAG, "Odd, nobody asked to unmount?");
2414 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002415 }
Kenny Root02c87302010-07-01 08:10:18 -07002416
Kenny Roota02b8b02010-08-05 16:14:17 -07002417 private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
2418 if (callerUid == android.os.Process.SYSTEM_UID) {
2419 return true;
2420 }
2421
Kenny Root02c87302010-07-01 08:10:18 -07002422 if (packageName == null) {
2423 return false;
2424 }
2425
Jeff Sharkeycd654482016-01-08 17:42:11 -07002426 final int packageUid = mPms.getPackageUid(packageName,
2427 PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callerUid));
Kenny Root02c87302010-07-01 08:10:18 -07002428
2429 if (DEBUG_OBB) {
2430 Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
2431 packageUid + ", callerUid = " + callerUid);
2432 }
2433
2434 return callerUid == packageUid;
2435 }
2436
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002437 public String getMountedObbPath(String rawPath) {
2438 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002439
Kenny Root02c87302010-07-01 08:10:18 -07002440 waitForReady();
2441 warnOnNotMounted();
2442
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002443 final ObbState state;
Rubin Xucd7a0142015-04-17 23:45:27 +01002444 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002445 state = mObbPathToStateMap.get(rawPath);
2446 }
2447 if (state == null) {
2448 Slog.w(TAG, "Failed to find OBB mounted at " + rawPath);
2449 return null;
2450 }
2451
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002452 final NativeDaemonEvent event;
Kenny Root02c87302010-07-01 08:10:18 -07002453 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07002454 event = mConnector.execute("obb", "path", state.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002455 event.checkCode(VoldResponseCode.AsecPathResult);
2456 return event.getMessage();
Kenny Root02c87302010-07-01 08:10:18 -07002457 } catch (NativeDaemonConnectorException e) {
2458 int code = e.getCode();
2459 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Kenny Roota02b8b02010-08-05 16:14:17 -07002460 return null;
Kenny Root02c87302010-07-01 08:10:18 -07002461 } else {
2462 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2463 }
2464 }
2465 }
2466
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002467 @Override
2468 public boolean isObbMounted(String rawPath) {
2469 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002470 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002471 return mObbPathToStateMap.containsKey(rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002472 }
Kenny Root02c87302010-07-01 08:10:18 -07002473 }
2474
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002475 @Override
2476 public void mountObb(
2477 String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) {
2478 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2479 Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
2480 Preconditions.checkNotNull(token, "token cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002481
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002482 final int callingUid = Binder.getCallingUid();
2483 final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce);
2484 final ObbAction action = new MountObbAction(obbState, key, callingUid);
Kenny Roota02b8b02010-08-05 16:14:17 -07002485 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
2486
2487 if (DEBUG_OBB)
2488 Slog.i(TAG, "Send to OBB handler: " + action.toString());
Kenny Root02c87302010-07-01 08:10:18 -07002489 }
2490
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002491 @Override
2492 public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
2493 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2494
2495 final ObbState existingState;
Rubin Xucd7a0142015-04-17 23:45:27 +01002496 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002497 existingState = mObbPathToStateMap.get(rawPath);
Kenny Rootf1121dc2010-09-29 07:30:53 -07002498 }
2499
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002500 if (existingState != null) {
2501 // TODO: separate state object from request data
2502 final int callingUid = Binder.getCallingUid();
2503 final ObbState newState = new ObbState(
2504 rawPath, existingState.canonicalPath, callingUid, token, nonce);
2505 final ObbAction action = new UnmountObbAction(newState, force);
2506 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root02c87302010-07-01 08:10:18 -07002507
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002508 if (DEBUG_OBB)
2509 Slog.i(TAG, "Send to OBB handler: " + action.toString());
2510 } else {
2511 Slog.w(TAG, "Unknown OBB mount at " + rawPath);
2512 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002513 }
2514
Ben Komalo444eca22011-09-01 15:17:44 -07002515 @Override
2516 public int getEncryptionState() {
2517 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2518 "no permission to access the crypt keeper");
2519
2520 waitForReady();
2521
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002522 final NativeDaemonEvent event;
Ben Komalo444eca22011-09-01 15:17:44 -07002523 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002524 event = mCryptConnector.execute("cryptfs", "cryptocomplete");
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002525 return Integer.parseInt(event.getMessage());
Ben Komalo444eca22011-09-01 15:17:44 -07002526 } catch (NumberFormatException e) {
2527 // Bad result - unexpected.
2528 Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
2529 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2530 } catch (NativeDaemonConnectorException e) {
2531 // Something bad happened.
2532 Slog.w(TAG, "Error in communicating with cryptfs in validating");
2533 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2534 }
2535 }
2536
2537 @Override
Jason parks5af0b912010-11-29 09:05:25 -06002538 public int decryptStorage(String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002539 if (TextUtils.isEmpty(password)) {
2540 throw new IllegalArgumentException("password cannot be empty");
Jason parks5af0b912010-11-29 09:05:25 -06002541 }
2542
Jason parks8888c592011-01-20 22:46:41 -06002543 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2544 "no permission to access the crypt keeper");
Jason parks5af0b912010-11-29 09:05:25 -06002545
2546 waitForReady();
2547
2548 if (DEBUG_EVENTS) {
2549 Slog.i(TAG, "decrypting storage...");
2550 }
2551
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002552 final NativeDaemonEvent event;
Jason parks5af0b912010-11-29 09:05:25 -06002553 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002554 event = mCryptConnector.execute("cryptfs", "checkpw", new SensitiveArg(password));
Jason parks9ed98bc2011-01-17 09:58:35 -06002555
Fredrik Roubertda6aedf2011-12-20 17:34:43 +01002556 final int code = Integer.parseInt(event.getMessage());
Jason parks9ed98bc2011-01-17 09:58:35 -06002557 if (code == 0) {
2558 // Decrypt was successful. Post a delayed message before restarting in order
2559 // to let the UI to clear itself
2560 mHandler.postDelayed(new Runnable() {
2561 public void run() {
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002562 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002563 mCryptConnector.execute("cryptfs", "restart");
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002564 } catch (NativeDaemonConnectorException e) {
2565 Slog.e(TAG, "problem executing in background", e);
2566 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002567 }
Jason parksf7b3cd42011-01-27 09:28:25 -06002568 }, 1000); // 1 second
Jason parks9ed98bc2011-01-17 09:58:35 -06002569 }
2570
2571 return code;
Jason parks5af0b912010-11-29 09:05:25 -06002572 } catch (NativeDaemonConnectorException e) {
2573 // Decryption failed
2574 return e.getCode();
2575 }
Jason parks5af0b912010-11-29 09:05:25 -06002576 }
2577
Paul Lawrence46791e72014-04-03 09:10:26 -07002578 public int encryptStorage(int type, String password) {
2579 if (TextUtils.isEmpty(password) && type != StorageManager.CRYPT_TYPE_DEFAULT) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002580 throw new IllegalArgumentException("password cannot be empty");
Jason parks56aa5322011-01-07 09:01:15 -06002581 }
2582
Jason parks8888c592011-01-20 22:46:41 -06002583 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2584 "no permission to access the crypt keeper");
Jason parks56aa5322011-01-07 09:01:15 -06002585
2586 waitForReady();
2587
2588 if (DEBUG_EVENTS) {
Jason parks8888c592011-01-20 22:46:41 -06002589 Slog.i(TAG, "encrypting storage...");
Jason parks56aa5322011-01-07 09:01:15 -06002590 }
2591
2592 try {
Paul Lawrence5096d9e2015-09-09 13:05:45 -07002593 if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
2594 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2595 CRYPTO_TYPES[type]);
2596 } else {
2597 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2598 CRYPTO_TYPES[type], new SensitiveArg(password));
2599 }
Jason parks56aa5322011-01-07 09:01:15 -06002600 } catch (NativeDaemonConnectorException e) {
2601 // Encryption failed
2602 return e.getCode();
2603 }
2604
2605 return 0;
2606 }
2607
Paul Lawrence8e397362014-01-27 15:22:30 -08002608 /** Set the password for encrypting the master key.
2609 * @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
2610 * @param password The password to set.
2611 */
2612 public int changeEncryptionPassword(int type, String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002613 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2614 "no permission to access the crypt keeper");
2615
2616 waitForReady();
2617
2618 if (DEBUG_EVENTS) {
2619 Slog.i(TAG, "changing encryption password...");
2620 }
2621
2622 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002623 NativeDaemonEvent event = mCryptConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type],
Paul Lawrence05487612015-06-09 13:35:38 -07002624 new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002625 return Integer.parseInt(event.getMessage());
Jason parksf7b3cd42011-01-27 09:28:25 -06002626 } catch (NativeDaemonConnectorException e) {
2627 // Encryption failed
2628 return e.getCode();
2629 }
2630 }
2631
Christopher Tate32418be2011-10-10 13:51:12 -07002632 /**
2633 * Validate a user-supplied password string with cryptfs
2634 */
2635 @Override
2636 public int verifyEncryptionPassword(String password) throws RemoteException {
2637 // Only the system process is permitted to validate passwords
2638 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2639 throw new SecurityException("no permission to access the crypt keeper");
2640 }
2641
2642 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2643 "no permission to access the crypt keeper");
2644
2645 if (TextUtils.isEmpty(password)) {
2646 throw new IllegalArgumentException("password cannot be empty");
2647 }
2648
2649 waitForReady();
2650
2651 if (DEBUG_EVENTS) {
2652 Slog.i(TAG, "validating encryption password...");
2653 }
2654
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002655 final NativeDaemonEvent event;
Christopher Tate32418be2011-10-10 13:51:12 -07002656 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002657 event = mCryptConnector.execute("cryptfs", "verifypw", new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002658 Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
2659 return Integer.parseInt(event.getMessage());
Christopher Tate32418be2011-10-10 13:51:12 -07002660 } catch (NativeDaemonConnectorException e) {
2661 // Encryption failed
2662 return e.getCode();
2663 }
2664 }
2665
Paul Lawrence8e397362014-01-27 15:22:30 -08002666 /**
2667 * Get the type of encryption used to encrypt the master key.
2668 * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
2669 */
2670 @Override
Svetoslav16e4a1a2014-09-29 18:16:20 -07002671 public int getPasswordType() {
Paul Lawrence9de713d2016-05-02 22:45:33 +00002672 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2673 "no permission to access the crypt keeper");
2674
Paul Lawrence8e397362014-01-27 15:22:30 -08002675 waitForReady();
2676
2677 final NativeDaemonEvent event;
2678 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002679 event = mCryptConnector.execute("cryptfs", "getpwtype");
Paul Lawrence8e397362014-01-27 15:22:30 -08002680 for (int i = 0; i < CRYPTO_TYPES.length; ++i) {
2681 if (CRYPTO_TYPES[i].equals(event.getMessage()))
2682 return i;
2683 }
2684
2685 throw new IllegalStateException("unexpected return from cryptfs");
2686 } catch (NativeDaemonConnectorException e) {
2687 throw e.rethrowAsParcelableException();
2688 }
2689 }
2690
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002691 /**
2692 * Set a field in the crypto header.
2693 * @param field field to set
2694 * @param contents contents to set in field
2695 */
2696 @Override
2697 public void setField(String field, String contents) throws RemoteException {
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002698 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2699 "no permission to access the crypt keeper");
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002700
2701 waitForReady();
2702
2703 final NativeDaemonEvent event;
2704 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002705 event = mCryptConnector.execute("cryptfs", "setfield", field, contents);
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002706 } catch (NativeDaemonConnectorException e) {
2707 throw e.rethrowAsParcelableException();
2708 }
2709 }
2710
2711 /**
2712 * Gets a field from the crypto header.
2713 * @param field field to get
2714 * @return contents of field
2715 */
2716 @Override
2717 public String getField(String field) throws RemoteException {
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002718 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2719 "no permission to access the crypt keeper");
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002720
2721 waitForReady();
2722
2723 final NativeDaemonEvent event;
2724 try {
2725 final String[] contents = NativeDaemonEvent.filterMessageList(
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002726 mCryptConnector.executeForList("cryptfs", "getfield", field),
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002727 VoldResponseCode.CryptfsGetfieldResult);
2728 String result = new String();
2729 for (String content : contents) {
2730 result += content;
2731 }
2732 return result;
2733 } catch (NativeDaemonConnectorException e) {
2734 throw e.rethrowAsParcelableException();
2735 }
2736 }
2737
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002738 /**
2739 * Is userdata convertible to file based encryption?
2740 * @return non zero for convertible
2741 */
2742 @Override
2743 public boolean isConvertibleToFBE() throws RemoteException {
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002744 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2745 "no permission to access the crypt keeper");
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002746
2747 waitForReady();
2748
2749 final NativeDaemonEvent event;
2750 try {
2751 event = mCryptConnector.execute("cryptfs", "isConvertibleToFBE");
2752 return Integer.parseInt(event.getMessage()) != 0;
2753 } catch (NativeDaemonConnectorException e) {
2754 throw e.rethrowAsParcelableException();
2755 }
2756 }
2757
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002758 @Override
Paul Lawrence945490c2014-03-27 16:37:28 +00002759 public String getPassword() throws RemoteException {
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002760 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
Rubin Xucd7a0142015-04-17 23:45:27 +01002761 "only keyguard can retrieve password");
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002762
Paul Lawrence945490c2014-03-27 16:37:28 +00002763 if (!isReady()) {
2764 return new String();
2765 }
2766
2767 final NativeDaemonEvent event;
2768 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002769 event = mCryptConnector.execute("cryptfs", "getpw");
Paul Lawrence24063b52015-01-06 13:11:23 -08002770 if ("-1".equals(event.getMessage())) {
2771 // -1 equals no password
2772 return null;
2773 }
Paul Lawrence05487612015-06-09 13:35:38 -07002774 return event.getMessage();
Paul Lawrence945490c2014-03-27 16:37:28 +00002775 } catch (NativeDaemonConnectorException e) {
2776 throw e.rethrowAsParcelableException();
Paul Lawrence24063b52015-01-06 13:11:23 -08002777 } catch (IllegalArgumentException e) {
2778 Slog.e(TAG, "Invalid response to getPassword");
2779 return null;
Paul Lawrence945490c2014-03-27 16:37:28 +00002780 }
2781 }
2782
2783 @Override
2784 public void clearPassword() throws RemoteException {
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002785 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2786 "only keyguard can clear password");
2787
Paul Lawrence945490c2014-03-27 16:37:28 +00002788 if (!isReady()) {
2789 return;
2790 }
2791
2792 final NativeDaemonEvent event;
2793 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002794 event = mCryptConnector.execute("cryptfs", "clearpw");
Paul Lawrence945490c2014-03-27 16:37:28 +00002795 } catch (NativeDaemonConnectorException e) {
2796 throw e.rethrowAsParcelableException();
2797 }
2798 }
2799
2800 @Override
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002801 public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002802 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002803 waitForReady();
2804
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002805 try {
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002806 mCryptConnector.execute("cryptfs", "create_user_key", userId, serialNumber,
2807 ephemeral ? 1 : 0);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002808 } catch (NativeDaemonConnectorException e) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002809 throw e.rethrowAsParcelableException();
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002810 }
2811 }
2812
Paul Crowley7ec733f2015-05-19 12:42:00 +01002813 @Override
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002814 public void destroyUserKey(int userId) {
2815 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowley7ec733f2015-05-19 12:42:00 +01002816 waitForReady();
2817
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002818 try {
2819 mCryptConnector.execute("cryptfs", "destroy_user_key", userId);
2820 } catch (NativeDaemonConnectorException e) {
2821 throw e.rethrowAsParcelableException();
2822 }
2823 }
2824
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002825 private SensitiveArg encodeBytes(byte[] bytes) {
2826 if (ArrayUtils.isEmpty(bytes)) {
2827 return new SensitiveArg("!");
2828 } else {
2829 return new SensitiveArg(HexDump.toHexString(bytes));
2830 }
2831 }
2832
Paul Crowleycc701552016-05-17 14:18:49 -07002833 /*
2834 * Add this token/secret pair to the set of ways we can recover a disk encryption key.
2835 * Changing the token/secret for a disk encryption key is done in two phases: first, adding
2836 * a new token/secret pair with this call, then delting all other pairs with
2837 * fixateNewestUserKeyAuth. This allows other places where a credential is used, such as
2838 * Gatekeeper, to be updated between the two calls.
2839 */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002840 @Override
Paul Crowleycc701552016-05-17 14:18:49 -07002841 public void addUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002842 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2843 waitForReady();
2844
2845 try {
Paul Crowleycc701552016-05-17 14:18:49 -07002846 mCryptConnector.execute("cryptfs", "add_user_key_auth", userId, serialNumber,
2847 encodeBytes(token), encodeBytes(secret));
2848 } catch (NativeDaemonConnectorException e) {
2849 throw e.rethrowAsParcelableException();
2850 }
2851 }
2852
2853 /*
2854 * Delete all disk encryption token/secret pairs except the most recently added one
2855 */
2856 @Override
2857 public void fixateNewestUserKeyAuth(int userId) {
2858 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2859 waitForReady();
2860
2861 try {
2862 mCryptConnector.execute("cryptfs", "fixate_newest_user_key_auth", userId);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002863 } catch (NativeDaemonConnectorException e) {
2864 throw e.rethrowAsParcelableException();
2865 }
2866 }
2867
2868 @Override
2869 public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002870 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2871 waitForReady();
2872
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002873 if (StorageManager.isFileEncryptedNativeOrEmulated()) {
2874 // When a user has secure lock screen, require a challenge token to
2875 // actually unlock. This check is mostly in place for emulation mode.
2876 if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(token)) {
2877 throw new IllegalStateException("Token required to unlock secure user " + userId);
2878 }
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07002879
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002880 try {
2881 mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber,
2882 encodeBytes(token), encodeBytes(secret));
2883 } catch (NativeDaemonConnectorException e) {
2884 throw e.rethrowAsParcelableException();
2885 }
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002886 }
2887
2888 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002889 mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002890 }
2891 }
2892
2893 @Override
2894 public void lockUserKey(int userId) {
2895 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2896 waitForReady();
2897
2898 try {
2899 mCryptConnector.execute("cryptfs", "lock_user_key", userId);
2900 } catch (NativeDaemonConnectorException e) {
2901 throw e.rethrowAsParcelableException();
2902 }
2903
2904 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002905 mLocalUnlockedUsers = ArrayUtils.removeInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002906 }
2907 }
2908
2909 @Override
2910 public boolean isUserKeyUnlocked(int userId) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002911 synchronized (mLock) {
2912 return ArrayUtils.contains(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002913 }
2914 }
2915
2916 @Override
Jeff Sharkey47f71082016-02-01 17:03:54 -07002917 public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002918 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2919 waitForReady();
2920
2921 try {
2922 mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid),
Jeff Sharkey47f71082016-02-01 17:03:54 -07002923 userId, serialNumber, flags);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002924 } catch (NativeDaemonConnectorException e) {
2925 throw e.rethrowAsParcelableException();
Paul Crowley7ec733f2015-05-19 12:42:00 +01002926 }
2927 }
2928
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002929 @Override
Jeff Sharkeyfcf1e552016-04-14 20:44:58 -06002930 public void destroyUserStorage(String volumeUuid, int userId, int flags) {
2931 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2932 waitForReady();
2933
2934 try {
2935 mCryptConnector.execute("cryptfs", "destroy_user_storage", escapeNull(volumeUuid),
2936 userId, flags);
2937 } catch (NativeDaemonConnectorException e) {
2938 throw e.rethrowAsParcelableException();
2939 }
2940 }
2941
2942 @Override
Daichi Hirono91e3b502015-12-16 09:24:16 +09002943 public ParcelFileDescriptor mountAppFuse(final String name) throws RemoteException {
Daichi Hironobee50c02015-12-14 11:00:54 +09002944 try {
Daichi Hirono91e3b502015-12-16 09:24:16 +09002945 final int uid = Binder.getCallingUid();
Daichi Hironofd7d57e2016-01-29 14:30:58 +09002946 final int pid = Binder.getCallingPid();
Daichi Hironobee50c02015-12-14 11:00:54 +09002947 final NativeDaemonEvent event =
Daichi Hironofd7d57e2016-01-29 14:30:58 +09002948 mConnector.execute("appfuse", "mount", uid, pid, name);
Daichi Hironobee50c02015-12-14 11:00:54 +09002949 if (event.getFileDescriptors() == null) {
Daichi Hirono91e3b502015-12-16 09:24:16 +09002950 throw new RemoteException("AppFuse FD from vold is null.");
Daichi Hironobee50c02015-12-14 11:00:54 +09002951 }
Daichi Hirono91e3b502015-12-16 09:24:16 +09002952 return ParcelFileDescriptor.fromFd(
2953 event.getFileDescriptors()[0],
2954 mHandler,
2955 new ParcelFileDescriptor.OnCloseListener() {
2956 @Override
2957 public void onClose(IOException e) {
2958 try {
2959 final NativeDaemonEvent event = mConnector.execute(
Daichi Hironofd7d57e2016-01-29 14:30:58 +09002960 "appfuse", "unmount", uid, pid, name);
Daichi Hirono91e3b502015-12-16 09:24:16 +09002961 } catch (NativeDaemonConnectorException unmountException) {
2962 Log.e(TAG, "Failed to unmount appfuse.");
2963 }
2964 }
2965 });
Daichi Hironobee50c02015-12-14 11:00:54 +09002966 } catch (NativeDaemonConnectorException e) {
2967 throw e.rethrowAsParcelableException();
Daichi Hirono91e3b502015-12-16 09:24:16 +09002968 } catch (IOException e) {
2969 throw new RemoteException(e.getMessage());
Daichi Hironobee50c02015-12-14 11:00:54 +09002970 }
Daichi Hirono9e8d9e22015-11-13 14:37:00 +09002971 }
2972
2973 @Override
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002974 public int mkdirs(String callingPkg, String appPath) {
2975 final int userId = UserHandle.getUserId(Binder.getCallingUid());
2976 final UserEnvironment userEnv = new UserEnvironment(userId);
2977
2978 // Validate that reported package name belongs to caller
2979 final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
2980 Context.APP_OPS_SERVICE);
2981 appOps.checkPackage(Binder.getCallingUid(), callingPkg);
2982
Jeff Sharkey48877892015-03-18 11:27:19 -07002983 File appFile = null;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002984 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07002985 appFile = new File(appPath).getCanonicalFile();
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002986 } catch (IOException e) {
2987 Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
2988 return -1;
2989 }
2990
2991 // Try translating the app path into a vold path, but require that it
2992 // belong to the calling package.
Jeff Sharkey48877892015-03-18 11:27:19 -07002993 if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) ||
2994 FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) ||
2995 FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) {
2996 appPath = appFile.getAbsolutePath();
2997 if (!appPath.endsWith("/")) {
2998 appPath = appPath + "/";
2999 }
3000
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003001 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07003002 mConnector.execute("volume", "mkdirs", appPath);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003003 return 0;
3004 } catch (NativeDaemonConnectorException e) {
3005 return e.getCode();
3006 }
3007 }
3008
Jeff Sharkey48877892015-03-18 11:27:19 -07003009 throw new SecurityException("Invalid mkdirs path: " + appFile);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003010 }
3011
3012 @Override
Jeff Sharkey46349872015-07-28 10:49:47 -07003013 public StorageVolume[] getVolumeList(int uid, String packageName, int flags) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003014 final int userId = UserHandle.getUserId(uid);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003015
Jeff Sharkey46349872015-07-28 10:49:47 -07003016 final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0;
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003017 final boolean realState = (flags & StorageManager.FLAG_REAL_STATE) != 0;
3018 final boolean includeInvisible = (flags & StorageManager.FLAG_INCLUDE_INVISIBLE) != 0;
Jeff Sharkey46349872015-07-28 10:49:47 -07003019
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003020 final boolean userKeyUnlocked;
3021 final boolean storagePermission;
3022 final long token = Binder.clearCallingIdentity();
Svetoslav38c3dbb2015-07-14 11:27:06 -07003023 try {
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003024 userKeyUnlocked = isUserKeyUnlocked(userId);
3025 storagePermission = mMountServiceInternal.hasExternalStorage(uid, packageName);
Svetoslav38c3dbb2015-07-14 11:27:06 -07003026 } finally {
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003027 Binder.restoreCallingIdentity(token);
Svetoslav38c3dbb2015-07-14 11:27:06 -07003028 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003029
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003030 boolean foundPrimary = false;
3031
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003032 final ArrayList<StorageVolume> res = new ArrayList<>();
Jeff Sharkey48877892015-03-18 11:27:19 -07003033 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003034 for (int i = 0; i < mVolumes.size(); i++) {
3035 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003036 switch (vol.getType()) {
3037 case VolumeInfo.TYPE_PUBLIC:
3038 case VolumeInfo.TYPE_EMULATED:
3039 break;
3040 default:
3041 continue;
3042 }
3043
3044 boolean match = false;
3045 if (forWrite) {
3046 match = vol.isVisibleForWrite(userId);
3047 } else {
Felipe Leme123a0e72016-06-10 11:09:11 -07003048 match = vol.isVisibleForRead(userId)
3049 || (includeInvisible && vol.getPath() != null);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003050 }
3051 if (!match) continue;
3052
3053 boolean reportUnmounted = false;
3054 if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !userKeyUnlocked) {
3055 reportUnmounted = true;
3056 } else if (!storagePermission && !realState) {
3057 reportUnmounted = true;
3058 }
3059
3060 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
3061 reportUnmounted);
3062 if (vol.isPrimary()) {
3063 res.add(0, userVol);
3064 foundPrimary = true;
3065 } else {
3066 res.add(userVol);
Jeff Sharkeyb049e212012-09-07 23:16:01 -07003067 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003068 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003069 }
Jeff Sharkey48877892015-03-18 11:27:19 -07003070
3071 if (!foundPrimary) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003072 Log.w(TAG, "No primary storage defined yet; hacking together a stub");
Jeff Sharkey48877892015-03-18 11:27:19 -07003073
3074 final boolean primaryPhysical = SystemProperties.getBoolean(
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003075 StorageManager.PROP_PRIMARY_PHYSICAL, false);
Jeff Sharkey48877892015-03-18 11:27:19 -07003076
3077 final String id = "stub_primary";
3078 final File path = Environment.getLegacyExternalStorageDirectory();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003079 final String description = mContext.getString(android.R.string.unknownName);
Jeff Sharkey48877892015-03-18 11:27:19 -07003080 final boolean primary = true;
3081 final boolean removable = primaryPhysical;
3082 final boolean emulated = !primaryPhysical;
3083 final long mtpReserveSize = 0L;
3084 final boolean allowMassStorage = false;
3085 final long maxFileSize = 0L;
3086 final UserHandle owner = new UserHandle(userId);
3087 final String uuid = null;
Jeff Sharkey48877892015-03-18 11:27:19 -07003088 final String state = Environment.MEDIA_REMOVED;
3089
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07003090 res.add(0, new StorageVolume(id, StorageVolume.STORAGE_ID_INVALID, path,
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003091 description, primary, removable, emulated, mtpReserveSize,
3092 allowMassStorage, maxFileSize, owner, uuid, state));
Jeff Sharkey48877892015-03-18 11:27:19 -07003093 }
3094
3095 return res.toArray(new StorageVolume[res.size()]);
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003096 }
3097
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003098 @Override
3099 public DiskInfo[] getDisks() {
3100 synchronized (mLock) {
3101 final DiskInfo[] res = new DiskInfo[mDisks.size()];
3102 for (int i = 0; i < mDisks.size(); i++) {
3103 res[i] = mDisks.valueAt(i);
3104 }
3105 return res;
3106 }
3107 }
3108
3109 @Override
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003110 public VolumeInfo[] getVolumes(int flags) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003111 synchronized (mLock) {
3112 final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
3113 for (int i = 0; i < mVolumes.size(); i++) {
3114 res[i] = mVolumes.valueAt(i);
3115 }
3116 return res;
3117 }
3118 }
3119
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003120 @Override
3121 public VolumeRecord[] getVolumeRecords(int flags) {
3122 synchronized (mLock) {
3123 final VolumeRecord[] res = new VolumeRecord[mRecords.size()];
3124 for (int i = 0; i < mRecords.size(); i++) {
3125 res[i] = mRecords.valueAt(i);
3126 }
3127 return res;
3128 }
3129 }
3130
Kenny Rootaf9d6672010-10-08 09:21:39 -07003131 private void addObbStateLocked(ObbState obbState) throws RemoteException {
3132 final IBinder binder = obbState.getBinder();
3133 List<ObbState> obbStates = mObbMounts.get(binder);
Kenny Root5919ac62010-10-05 09:49:40 -07003134
Kenny Rootaf9d6672010-10-08 09:21:39 -07003135 if (obbStates == null) {
3136 obbStates = new ArrayList<ObbState>();
3137 mObbMounts.put(binder, obbStates);
3138 } else {
3139 for (final ObbState o : obbStates) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003140 if (o.rawPath.equals(obbState.rawPath)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003141 throw new IllegalStateException("Attempt to add ObbState twice. "
3142 + "This indicates an error in the MountService logic.");
Kenny Root5919ac62010-10-05 09:49:40 -07003143 }
3144 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003145 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003146
3147 obbStates.add(obbState);
3148 try {
3149 obbState.link();
3150 } catch (RemoteException e) {
3151 /*
3152 * The binder died before we could link it, so clean up our state
3153 * and return failure.
3154 */
3155 obbStates.remove(obbState);
3156 if (obbStates.isEmpty()) {
3157 mObbMounts.remove(binder);
3158 }
3159
3160 // Rethrow the error so mountObb can get it
3161 throw e;
3162 }
3163
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003164 mObbPathToStateMap.put(obbState.rawPath, obbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003165 }
3166
Kenny Rootaf9d6672010-10-08 09:21:39 -07003167 private void removeObbStateLocked(ObbState obbState) {
3168 final IBinder binder = obbState.getBinder();
3169 final List<ObbState> obbStates = mObbMounts.get(binder);
3170 if (obbStates != null) {
3171 if (obbStates.remove(obbState)) {
3172 obbState.unlink();
Kenny Root05105f72010-09-22 17:29:43 -07003173 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003174 if (obbStates.isEmpty()) {
3175 mObbMounts.remove(binder);
3176 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003177 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003178
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003179 mObbPathToStateMap.remove(obbState.rawPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003180 }
3181
Kenny Roota02b8b02010-08-05 16:14:17 -07003182 private class ObbActionHandler extends Handler {
3183 private boolean mBound = false;
Kenny Root480afe72010-10-07 10:17:50 -07003184 private final List<ObbAction> mActions = new LinkedList<ObbAction>();
Kenny Roota02b8b02010-08-05 16:14:17 -07003185
3186 ObbActionHandler(Looper l) {
3187 super(l);
3188 }
3189
3190 @Override
3191 public void handleMessage(Message msg) {
3192 switch (msg.what) {
3193 case OBB_RUN_ACTION: {
Kenny Root480afe72010-10-07 10:17:50 -07003194 final ObbAction action = (ObbAction) msg.obj;
Kenny Roota02b8b02010-08-05 16:14:17 -07003195
3196 if (DEBUG_OBB)
3197 Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
3198
3199 // If a bind was already initiated we don't really
3200 // need to do anything. The pending install
3201 // will be processed later on.
3202 if (!mBound) {
3203 // If this is the only one pending we might
3204 // have to bind to the service again.
3205 if (!connectToService()) {
3206 Slog.e(TAG, "Failed to bind to media container service");
3207 action.handleError();
3208 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003209 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003210 }
Kenny Root735de3b2010-09-30 14:11:39 -07003211
Kenny Root735de3b2010-09-30 14:11:39 -07003212 mActions.add(action);
Kenny Roota02b8b02010-08-05 16:14:17 -07003213 break;
3214 }
3215 case OBB_MCS_BOUND: {
3216 if (DEBUG_OBB)
3217 Slog.i(TAG, "OBB_MCS_BOUND");
3218 if (msg.obj != null) {
3219 mContainerService = (IMediaContainerService) msg.obj;
3220 }
3221 if (mContainerService == null) {
3222 // Something seriously wrong. Bail out
3223 Slog.e(TAG, "Cannot bind to media container service");
3224 for (ObbAction action : mActions) {
3225 // Indicate service bind error
3226 action.handleError();
3227 }
3228 mActions.clear();
3229 } else if (mActions.size() > 0) {
Kenny Root480afe72010-10-07 10:17:50 -07003230 final ObbAction action = mActions.get(0);
Kenny Roota02b8b02010-08-05 16:14:17 -07003231 if (action != null) {
3232 action.execute(this);
3233 }
3234 } else {
3235 // Should never happen ideally.
3236 Slog.w(TAG, "Empty queue");
3237 }
3238 break;
3239 }
3240 case OBB_MCS_RECONNECT: {
3241 if (DEBUG_OBB)
3242 Slog.i(TAG, "OBB_MCS_RECONNECT");
3243 if (mActions.size() > 0) {
3244 if (mBound) {
3245 disconnectService();
3246 }
3247 if (!connectToService()) {
3248 Slog.e(TAG, "Failed to bind to media container service");
3249 for (ObbAction action : mActions) {
3250 // Indicate service bind error
3251 action.handleError();
3252 }
3253 mActions.clear();
3254 }
3255 }
3256 break;
3257 }
3258 case OBB_MCS_UNBIND: {
3259 if (DEBUG_OBB)
3260 Slog.i(TAG, "OBB_MCS_UNBIND");
3261
3262 // Delete pending install
3263 if (mActions.size() > 0) {
3264 mActions.remove(0);
3265 }
3266 if (mActions.size() == 0) {
3267 if (mBound) {
3268 disconnectService();
3269 }
3270 } else {
3271 // There are more pending requests in queue.
3272 // Just post MCS_BOUND message to trigger processing
3273 // of next pending install.
3274 mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
3275 }
3276 break;
3277 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003278 case OBB_FLUSH_MOUNT_STATE: {
3279 final String path = (String) msg.obj;
3280
3281 if (DEBUG_OBB)
3282 Slog.i(TAG, "Flushing all OBB state for path " + path);
3283
3284 synchronized (mObbMounts) {
3285 final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
3286
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003287 final Iterator<ObbState> i = mObbPathToStateMap.values().iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003288 while (i.hasNext()) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003289 final ObbState state = i.next();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003290
3291 /*
3292 * If this entry's source file is in the volume path
3293 * that got unmounted, remove it because it's no
3294 * longer valid.
3295 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003296 if (state.canonicalPath.startsWith(path)) {
3297 obbStatesToRemove.add(state);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003298 }
3299 }
3300
3301 for (final ObbState obbState : obbStatesToRemove) {
3302 if (DEBUG_OBB)
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003303 Slog.i(TAG, "Removing state for " + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003304
3305 removeObbStateLocked(obbState);
3306
3307 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003308 obbState.token.onObbResult(obbState.rawPath, obbState.nonce,
Kenny Rootaf9d6672010-10-08 09:21:39 -07003309 OnObbStateChangeListener.UNMOUNTED);
3310 } catch (RemoteException e) {
3311 Slog.i(TAG, "Couldn't send unmount notification for OBB: "
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003312 + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003313 }
3314 }
3315 }
3316 break;
3317 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003318 }
3319 }
3320
3321 private boolean connectToService() {
3322 if (DEBUG_OBB)
3323 Slog.i(TAG, "Trying to bind to DefaultContainerService");
3324
3325 Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Jeff Sharkey6dce4962015-07-03 18:08:41 -07003326 if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE,
Xiaohui Chene4de5a02015-09-22 15:33:31 -07003327 UserHandle.SYSTEM)) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003328 mBound = true;
3329 return true;
3330 }
3331 return false;
3332 }
3333
3334 private void disconnectService() {
3335 mContainerService = null;
3336 mBound = false;
3337 mContext.unbindService(mDefContainerConn);
3338 }
3339 }
3340
3341 abstract class ObbAction {
3342 private static final int MAX_RETRIES = 3;
3343 private int mRetries;
3344
3345 ObbState mObbState;
3346
3347 ObbAction(ObbState obbState) {
3348 mObbState = obbState;
3349 }
3350
3351 public void execute(ObbActionHandler handler) {
3352 try {
3353 if (DEBUG_OBB)
Ben Komalo444eca22011-09-01 15:17:44 -07003354 Slog.i(TAG, "Starting to execute action: " + toString());
Kenny Roota02b8b02010-08-05 16:14:17 -07003355 mRetries++;
3356 if (mRetries > MAX_RETRIES) {
3357 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
Kenny Root480afe72010-10-07 10:17:50 -07003358 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003359 handleError();
Kenny Roota02b8b02010-08-05 16:14:17 -07003360 } else {
3361 handleExecute();
3362 if (DEBUG_OBB)
3363 Slog.i(TAG, "Posting install MCS_UNBIND");
3364 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
3365 }
3366 } catch (RemoteException e) {
3367 if (DEBUG_OBB)
3368 Slog.i(TAG, "Posting install MCS_RECONNECT");
3369 mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
3370 } catch (Exception e) {
3371 if (DEBUG_OBB)
3372 Slog.d(TAG, "Error handling OBB action", e);
3373 handleError();
Kenny Root17eb6fb2010-10-06 15:02:52 -07003374 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003375 }
3376 }
3377
Kenny Root05105f72010-09-22 17:29:43 -07003378 abstract void handleExecute() throws RemoteException, IOException;
Kenny Roota02b8b02010-08-05 16:14:17 -07003379 abstract void handleError();
Kenny Root38cf8862010-09-26 14:18:51 -07003380
3381 protected ObbInfo getObbInfo() throws IOException {
3382 ObbInfo obbInfo;
3383 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003384 obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003385 } catch (RemoteException e) {
3386 Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003387 + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003388 obbInfo = null;
3389 }
3390 if (obbInfo == null) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003391 throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003392 }
3393 return obbInfo;
3394 }
3395
Kenny Rootaf9d6672010-10-08 09:21:39 -07003396 protected void sendNewStatusOrIgnore(int status) {
3397 if (mObbState == null || mObbState.token == null) {
3398 return;
3399 }
3400
Kenny Root38cf8862010-09-26 14:18:51 -07003401 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003402 mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
Kenny Root38cf8862010-09-26 14:18:51 -07003403 } catch (RemoteException e) {
3404 Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
3405 }
3406 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003407 }
3408
3409 class MountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003410 private final String mKey;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003411 private final int mCallingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003412
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003413 MountObbAction(ObbState obbState, String key, int callingUid) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003414 super(obbState);
3415 mKey = key;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003416 mCallingUid = callingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003417 }
3418
Jason parks5af0b912010-11-29 09:05:25 -06003419 @Override
Kenny Root735de3b2010-09-30 14:11:39 -07003420 public void handleExecute() throws IOException, RemoteException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003421 waitForReady();
3422 warnOnNotMounted();
3423
Kenny Root38cf8862010-09-26 14:18:51 -07003424 final ObbInfo obbInfo = getObbInfo();
3425
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003426 if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003427 Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
3428 + " which is owned by " + obbInfo.packageName);
3429 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3430 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003431 }
3432
Kenny Rootaf9d6672010-10-08 09:21:39 -07003433 final boolean isMounted;
3434 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003435 isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003436 }
3437 if (isMounted) {
3438 Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
3439 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
3440 return;
3441 }
3442
Kenny Rootaf9d6672010-10-08 09:21:39 -07003443 final String hashedKey;
3444 if (mKey == null) {
3445 hashedKey = "none";
3446 } else {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003447 try {
Kenny Root3b1abba2010-10-13 15:00:07 -07003448 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
3449
3450 KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
3451 PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
3452 SecretKey key = factory.generateSecret(ks);
3453 BigInteger bi = new BigInteger(key.getEncoded());
3454 hashedKey = bi.toString(16);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003455 } catch (NoSuchAlgorithmException e) {
Kenny Root3b1abba2010-10-13 15:00:07 -07003456 Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
3457 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
3458 return;
3459 } catch (InvalidKeySpecException e) {
3460 Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
3461 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root38cf8862010-09-26 14:18:51 -07003462 return;
3463 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003464 }
Kenny Root38cf8862010-09-26 14:18:51 -07003465
Kenny Rootaf9d6672010-10-08 09:21:39 -07003466 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003467 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003468 mConnector.execute("obb", "mount", mObbState.canonicalPath, new SensitiveArg(hashedKey),
Jeff Sharkey56cd6462013-06-07 15:09:15 -07003469 mObbState.ownerGid);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003470 } catch (NativeDaemonConnectorException e) {
3471 int code = e.getCode();
3472 if (code != VoldResponseCode.OpFailedStorageBusy) {
3473 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003474 }
3475 }
3476
Kenny Rootaf9d6672010-10-08 09:21:39 -07003477 if (rc == StorageResultCode.OperationSucceeded) {
3478 if (DEBUG_OBB)
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003479 Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003480
3481 synchronized (mObbMounts) {
3482 addObbStateLocked(mObbState);
3483 }
3484
3485 sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
Kenny Root02c87302010-07-01 08:10:18 -07003486 } else {
Kenny Root05105f72010-09-22 17:29:43 -07003487 Slog.e(TAG, "Couldn't mount OBB file: " + rc);
Kenny Roota02b8b02010-08-05 16:14:17 -07003488
Kenny Rootaf9d6672010-10-08 09:21:39 -07003489 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
Kenny Root02c87302010-07-01 08:10:18 -07003490 }
3491 }
3492
Jason parks5af0b912010-11-29 09:05:25 -06003493 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003494 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003495 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root02c87302010-07-01 08:10:18 -07003496 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003497
3498 @Override
3499 public String toString() {
3500 StringBuilder sb = new StringBuilder();
3501 sb.append("MountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003502 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003503 sb.append('}');
3504 return sb.toString();
3505 }
3506 }
3507
3508 class UnmountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003509 private final boolean mForceUnmount;
Kenny Roota02b8b02010-08-05 16:14:17 -07003510
3511 UnmountObbAction(ObbState obbState, boolean force) {
3512 super(obbState);
3513 mForceUnmount = force;
3514 }
3515
Jason parks5af0b912010-11-29 09:05:25 -06003516 @Override
Kenny Root38cf8862010-09-26 14:18:51 -07003517 public void handleExecute() throws IOException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003518 waitForReady();
3519 warnOnNotMounted();
3520
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003521 final ObbState existingState;
Kenny Root38cf8862010-09-26 14:18:51 -07003522 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003523 existingState = mObbPathToStateMap.get(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003524 }
Kenny Root38cf8862010-09-26 14:18:51 -07003525
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003526 if (existingState == null) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003527 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
3528 return;
3529 }
3530
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003531 if (existingState.ownerGid != mObbState.ownerGid) {
3532 Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
3533 + " (owned by GID " + existingState.ownerGid + ")");
Kenny Rootaf9d6672010-10-08 09:21:39 -07003534 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3535 return;
3536 }
3537
Kenny Rootaf9d6672010-10-08 09:21:39 -07003538 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003539 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003540 final Command cmd = new Command("obb", "unmount", mObbState.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08003541 if (mForceUnmount) {
3542 cmd.appendArg("force");
3543 }
3544 mConnector.execute(cmd);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003545 } catch (NativeDaemonConnectorException e) {
3546 int code = e.getCode();
3547 if (code == VoldResponseCode.OpFailedStorageBusy) {
3548 rc = StorageResultCode.OperationFailedStorageBusy;
3549 } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
3550 // If it's not mounted then we've already won.
3551 rc = StorageResultCode.OperationSucceeded;
3552 } else {
3553 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003554 }
3555 }
3556
Kenny Rootaf9d6672010-10-08 09:21:39 -07003557 if (rc == StorageResultCode.OperationSucceeded) {
3558 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003559 removeObbStateLocked(existingState);
Kenny Root38cf8862010-09-26 14:18:51 -07003560 }
3561
Kenny Rootaf9d6672010-10-08 09:21:39 -07003562 sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
Kenny Roota02b8b02010-08-05 16:14:17 -07003563 } else {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003564 Slog.w(TAG, "Could not unmount OBB: " + existingState);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003565 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
Kenny Roota02b8b02010-08-05 16:14:17 -07003566 }
3567 }
3568
Jason parks5af0b912010-11-29 09:05:25 -06003569 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003570 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003571 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Roota02b8b02010-08-05 16:14:17 -07003572 }
3573
3574 @Override
3575 public String toString() {
3576 StringBuilder sb = new StringBuilder();
3577 sb.append("UnmountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003578 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003579 sb.append(",force=");
3580 sb.append(mForceUnmount);
Kenny Roota02b8b02010-08-05 16:14:17 -07003581 sb.append('}');
3582 return sb.toString();
3583 }
Kenny Root02c87302010-07-01 08:10:18 -07003584 }
Kenny Root38cf8862010-09-26 14:18:51 -07003585
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003586 private static class Callbacks extends Handler {
3587 private static final int MSG_STORAGE_STATE_CHANGED = 1;
3588 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003589 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
3590 private static final int MSG_VOLUME_FORGOTTEN = 4;
3591 private static final int MSG_DISK_SCANNED = 5;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003592 private static final int MSG_DISK_DESTROYED = 6;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003593
3594 private final RemoteCallbackList<IMountServiceListener>
3595 mCallbacks = new RemoteCallbackList<>();
3596
3597 public Callbacks(Looper looper) {
3598 super(looper);
3599 }
3600
3601 public void register(IMountServiceListener callback) {
3602 mCallbacks.register(callback);
3603 }
3604
3605 public void unregister(IMountServiceListener callback) {
3606 mCallbacks.unregister(callback);
3607 }
3608
3609 @Override
3610 public void handleMessage(Message msg) {
3611 final SomeArgs args = (SomeArgs) msg.obj;
3612 final int n = mCallbacks.beginBroadcast();
3613 for (int i = 0; i < n; i++) {
3614 final IMountServiceListener callback = mCallbacks.getBroadcastItem(i);
3615 try {
3616 invokeCallback(callback, msg.what, args);
3617 } catch (RemoteException ignored) {
3618 }
3619 }
3620 mCallbacks.finishBroadcast();
3621 args.recycle();
3622 }
3623
3624 private void invokeCallback(IMountServiceListener callback, int what, SomeArgs args)
3625 throws RemoteException {
3626 switch (what) {
3627 case MSG_STORAGE_STATE_CHANGED: {
3628 callback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
3629 (String) args.arg3);
3630 break;
3631 }
3632 case MSG_VOLUME_STATE_CHANGED: {
3633 callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
3634 break;
3635 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07003636 case MSG_VOLUME_RECORD_CHANGED: {
3637 callback.onVolumeRecordChanged((VolumeRecord) args.arg1);
3638 break;
3639 }
3640 case MSG_VOLUME_FORGOTTEN: {
3641 callback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003642 break;
3643 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003644 case MSG_DISK_SCANNED: {
3645 callback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003646 break;
3647 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003648 case MSG_DISK_DESTROYED: {
3649 callback.onDiskDestroyed((DiskInfo) args.arg1);
3650 break;
3651 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003652 }
3653 }
3654
3655 private void notifyStorageStateChanged(String path, String oldState, String newState) {
3656 final SomeArgs args = SomeArgs.obtain();
3657 args.arg1 = path;
3658 args.arg2 = oldState;
3659 args.arg3 = newState;
3660 obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
3661 }
3662
3663 private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
3664 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003665 args.arg1 = vol.clone();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003666 args.argi2 = oldState;
3667 args.argi3 = newState;
3668 obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
3669 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003670
Jeff Sharkey50a05452015-04-29 11:24:52 -07003671 private void notifyVolumeRecordChanged(VolumeRecord rec) {
3672 final SomeArgs args = SomeArgs.obtain();
3673 args.arg1 = rec.clone();
3674 obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
3675 }
3676
3677 private void notifyVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003678 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003679 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003680 obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003681 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003682
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003683 private void notifyDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003684 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003685 args.arg1 = disk.clone();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003686 args.argi2 = volumeCount;
3687 obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003688 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003689
3690 private void notifyDiskDestroyed(DiskInfo disk) {
3691 final SomeArgs args = SomeArgs.obtain();
3692 args.arg1 = disk.clone();
3693 obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
3694 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003695 }
3696
Kenny Root38cf8862010-09-26 14:18:51 -07003697 @Override
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003698 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
3699 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
3700
3701 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003702 synchronized (mLock) {
3703 pw.println("Disks:");
3704 pw.increaseIndent();
3705 for (int i = 0; i < mDisks.size(); i++) {
3706 final DiskInfo disk = mDisks.valueAt(i);
3707 disk.dump(pw);
3708 }
3709 pw.decreaseIndent();
3710
3711 pw.println();
3712 pw.println("Volumes:");
3713 pw.increaseIndent();
3714 for (int i = 0; i < mVolumes.size(); i++) {
3715 final VolumeInfo vol = mVolumes.valueAt(i);
3716 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue;
3717 vol.dump(pw);
3718 }
3719 pw.decreaseIndent();
3720
3721 pw.println();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003722 pw.println("Records:");
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003723 pw.increaseIndent();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003724 for (int i = 0; i < mRecords.size(); i++) {
3725 final VolumeRecord note = mRecords.valueAt(i);
3726 note.dump(pw);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003727 }
3728 pw.decreaseIndent();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07003729
3730 pw.println();
3731 pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07003732 pw.println("Force adoptable: " + mForceAdoptable);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08003733 pw.println();
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003734 pw.println("Local unlocked users: " + Arrays.toString(mLocalUnlockedUsers));
3735 pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003736 }
Kenny Root38cf8862010-09-26 14:18:51 -07003737
Kenny Root38cf8862010-09-26 14:18:51 -07003738 synchronized (mObbMounts) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003739 pw.println();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003740 pw.println("mObbMounts:");
3741 pw.increaseIndent();
3742 final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet()
3743 .iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003744 while (binders.hasNext()) {
3745 Entry<IBinder, List<ObbState>> e = binders.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003746 pw.println(e.getKey() + ":");
3747 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003748 final List<ObbState> obbStates = e.getValue();
Kenny Root38cf8862010-09-26 14:18:51 -07003749 for (final ObbState obbState : obbStates) {
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003750 pw.println(obbState);
Kenny Root38cf8862010-09-26 14:18:51 -07003751 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003752 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003753 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003754 pw.decreaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003755
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003756 pw.println();
3757 pw.println("mObbPathToStateMap:");
3758 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003759 final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
3760 while (maps.hasNext()) {
3761 final Entry<String, ObbState> e = maps.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003762 pw.print(e.getKey());
3763 pw.print(" -> ");
3764 pw.println(e.getValue());
Kenny Rootaf9d6672010-10-08 09:21:39 -07003765 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003766 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003767 }
Kenny Root4161f9b2011-07-13 09:48:33 -07003768
Robert Greenwalt470fd722012-01-18 12:51:15 -08003769 pw.println();
Jeff Sharkey5b0e5202015-12-18 17:18:09 -07003770 pw.println("mConnector:");
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003771 pw.increaseIndent();
Robert Greenwalt470fd722012-01-18 12:51:15 -08003772 mConnector.dump(fd, pw, args);
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003773 pw.decreaseIndent();
Christopher Tate7265abe2014-11-21 13:54:45 -08003774
Christopher Tate7265abe2014-11-21 13:54:45 -08003775 pw.println();
Jeff Sharkey5b0e5202015-12-18 17:18:09 -07003776 pw.println("mCryptConnector:");
3777 pw.increaseIndent();
3778 mCryptConnector.dump(fd, pw, args);
3779 pw.decreaseIndent();
3780
3781 pw.println();
Christopher Tate7265abe2014-11-21 13:54:45 -08003782 pw.print("Last maintenance: ");
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07003783 pw.println(TimeUtils.formatForLogging(mLastMaintenance));
Kenny Root38cf8862010-09-26 14:18:51 -07003784 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003785
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003786 /** {@inheritDoc} */
Jeff Sharkey48877892015-03-18 11:27:19 -07003787 @Override
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003788 public void monitor() {
3789 if (mConnector != null) {
3790 mConnector.monitor();
3791 }
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07003792 if (mCryptConnector != null) {
3793 mCryptConnector.monitor();
3794 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003795 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003796
3797 private final class MountServiceInternalImpl extends MountServiceInternal {
3798 // Not guarded by a lock.
3799 private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
3800 new CopyOnWriteArrayList<>();
3801
3802 @Override
3803 public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
3804 // No locking - CopyOnWriteArrayList
3805 mPolicies.add(policy);
3806 }
3807
3808 @Override
3809 public void onExternalStoragePolicyChanged(int uid, String packageName) {
3810 final int mountMode = getExternalStorageMountMode(uid, packageName);
3811 remountUidExternalStorage(uid, mountMode);
3812 }
3813
3814 @Override
3815 public int getExternalStorageMountMode(int uid, String packageName) {
3816 // No locking - CopyOnWriteArrayList
3817 int mountMode = Integer.MAX_VALUE;
3818 for (ExternalStorageMountPolicy policy : mPolicies) {
3819 final int policyMode = policy.getMountMode(uid, packageName);
3820 if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
3821 return Zygote.MOUNT_EXTERNAL_NONE;
3822 }
3823 mountMode = Math.min(mountMode, policyMode);
3824 }
3825 if (mountMode == Integer.MAX_VALUE) {
3826 return Zygote.MOUNT_EXTERNAL_NONE;
3827 }
3828 return mountMode;
3829 }
3830
3831 public boolean hasExternalStorage(int uid, String packageName) {
Amith Yamasani2bd5cff2015-07-22 14:42:31 -07003832 // No need to check for system uid. This avoids a deadlock between
3833 // PackageManagerService and AppOpsService.
3834 if (uid == Process.SYSTEM_UID) {
3835 return true;
3836 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003837 // No locking - CopyOnWriteArrayList
3838 for (ExternalStorageMountPolicy policy : mPolicies) {
3839 final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
3840 if (!policyHasStorage) {
3841 return false;
3842 }
3843 }
3844 return true;
3845 }
3846 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003847}