blob: 3ce44526d17b68183b6611334422aa7295d66594 [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);
168 }
169
170 @Override
171 public void onBootPhase(int phase) {
172 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
173 mMountService.systemReady();
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900174 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
175 mMountService.bootCompleted();
Jeff Sharkey56e62932015-03-21 20:41:00 -0700176 }
177 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700178
179 @Override
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700180 public void onUnlockUser(int userHandle) {
181 mMountService.onUnlockUser(userHandle);
Jeff Sharkey48877892015-03-18 11:27:19 -0700182 }
183
184 @Override
185 public void onCleanupUser(int userHandle) {
186 mMountService.onCleanupUser(userHandle);
187 }
Jeff Sharkey56e62932015-03-21 20:41:00 -0700188 }
189
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800190 private static final boolean DEBUG_EVENTS = false;
Kenny Rootb7db2722011-01-25 16:39:35 -0800191 private static final boolean DEBUG_OBB = false;
Kenny Root02c87302010-07-01 08:10:18 -0700192
Kenny Root07714d42011-08-17 17:49:28 -0700193 // Disable this since it messes up long-running cryptfs operations.
194 private static final boolean WATCHDOG_ENABLE = false;
195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 private static final String TAG = "MountService";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700197
Jeff Sharkey9756d752015-05-14 21:07:42 -0700198 private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700199 private static final String TAG_STORAGE_TRIM = "storage_trim";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200
Kenny Root305bcbf2010-09-03 07:56:38 -0700201 private static final String VOLD_TAG = "VoldConnector";
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700202 private static final String CRYPTD_TAG = "CryptdConnector";
Kenny Root305bcbf2010-09-03 07:56:38 -0700203
Kenny Rootcf0b38c2011-03-22 14:17:59 -0700204 /** Maximum number of ASEC containers allowed to be mounted. */
205 private static final int MAX_CONTAINERS = 250;
206
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700207 /** Magic value sent by MoveTask.cpp */
208 private static final int MOVE_STATUS_COPY_FINISHED = 82;
209
San Mehat4270e1e2010-01-29 05:32:19 -0800210 /*
211 * Internal vold response code constants
212 */
San Mehat22dd86e2010-01-12 12:21:18 -0800213 class VoldResponseCode {
San Mehat4270e1e2010-01-29 05:32:19 -0800214 /*
215 * 100 series - Requestion action was initiated; expect another reply
216 * before proceeding with a new command.
217 */
San Mehat22dd86e2010-01-12 12:21:18 -0800218 public static final int VolumeListResult = 110;
219 public static final int AsecListResult = 111;
San Mehatc1b4ce92010-02-16 17:13:03 -0800220 public static final int StorageUsersListResult = 112;
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700221 public static final int CryptfsGetfieldResult = 113;
San Mehat22dd86e2010-01-12 12:21:18 -0800222
San Mehat4270e1e2010-01-29 05:32:19 -0800223 /*
224 * 200 series - Requestion action has been successfully completed.
225 */
226 public static final int ShareStatusResult = 210;
San Mehat22dd86e2010-01-12 12:21:18 -0800227 public static final int AsecPathResult = 211;
San Mehat4270e1e2010-01-29 05:32:19 -0800228 public static final int ShareEnabledResult = 212;
San Mehat22dd86e2010-01-12 12:21:18 -0800229
San Mehat4270e1e2010-01-29 05:32:19 -0800230 /*
231 * 400 series - Command was accepted, but the requested action
232 * did not take place.
233 */
234 public static final int OpFailedNoMedia = 401;
235 public static final int OpFailedMediaBlank = 402;
236 public static final int OpFailedMediaCorrupt = 403;
237 public static final int OpFailedVolNotMounted = 404;
San Mehatd9709982010-02-18 11:43:03 -0800238 public static final int OpFailedStorageBusy = 405;
San Mehat2d66cef2010-03-23 11:12:52 -0700239 public static final int OpFailedStorageNotFound = 406;
San Mehat4270e1e2010-01-29 05:32:19 -0800240
241 /*
242 * 600 series - Unsolicited broadcasts.
243 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700244 public static final int DISK_CREATED = 640;
245 public static final int DISK_SIZE_CHANGED = 641;
246 public static final int DISK_LABEL_CHANGED = 642;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700247 public static final int DISK_SCANNED = 643;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700248 public static final int DISK_SYS_PATH_CHANGED = 644;
Jeff Sharkey48877892015-03-18 11:27:19 -0700249 public static final int DISK_DESTROYED = 649;
250
251 public static final int VOLUME_CREATED = 650;
252 public static final int VOLUME_STATE_CHANGED = 651;
253 public static final int VOLUME_FS_TYPE_CHANGED = 652;
254 public static final int VOLUME_FS_UUID_CHANGED = 653;
255 public static final int VOLUME_FS_LABEL_CHANGED = 654;
256 public static final int VOLUME_PATH_CHANGED = 655;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700257 public static final int VOLUME_INTERNAL_PATH_CHANGED = 656;
Jeff Sharkey48877892015-03-18 11:27:19 -0700258 public static final int VOLUME_DESTROYED = 659;
Svetoslavf23b64d2013-04-25 14:45:54 -0700259
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700260 public static final int MOVE_STATUS = 660;
Jeff Sharkey9756d752015-05-14 21:07:42 -0700261 public static final int BENCHMARK_RESULT = 661;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700262 public static final int TRIM_RESULT = 662;
San Mehat22dd86e2010-01-12 12:21:18 -0800263 }
264
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700265 private static final int VERSION_INIT = 1;
266 private static final int VERSION_ADD_PRIMARY = 2;
Jeff Sharkeyfced5342015-05-10 14:53:34 -0700267 private static final int VERSION_FIX_PRIMARY = 3;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700268
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700269 private static final String TAG_VOLUMES = "volumes";
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700270 private static final String ATTR_VERSION = "version";
271 private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid";
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700272 private static final String ATTR_FORCE_ADOPTABLE = "forceAdoptable";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700273 private static final String TAG_VOLUME = "volume";
274 private static final String ATTR_TYPE = "type";
275 private static final String ATTR_FS_UUID = "fsUuid";
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700276 private static final String ATTR_PART_GUID = "partGuid";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700277 private static final String ATTR_NICKNAME = "nickname";
278 private static final String ATTR_USER_FLAGS = "userFlags";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700279 private static final String ATTR_CREATED_MILLIS = "createdMillis";
280 private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis";
281 private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700282
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700283 private final AtomicFile mSettingsFile;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700284
Jeff Sharkey48877892015-03-18 11:27:19 -0700285 /**
286 * <em>Never</em> hold the lock while performing downcalls into vold, since
287 * unsolicited events can suddenly appear to update data structures.
288 */
289 private final Object mLock = new Object();
290
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700291 /** Set of users that we know are unlocked. */
Jeff Sharkey48877892015-03-18 11:27:19 -0700292 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700293 private int[] mLocalUnlockedUsers = EmptyArray.INT;
294 /** Set of users that system knows are unlocked. */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800295 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700296 private int[] mSystemUnlockedUsers = EmptyArray.INT;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700297
298 /** Map from disk ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700299 @GuardedBy("mLock")
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700300 private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700301 /** Map from volume ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700302 @GuardedBy("mLock")
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700303 private final ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
Jeff Sharkey48877892015-03-18 11:27:19 -0700304
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700305 /** Map from UUID to record */
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700306 @GuardedBy("mLock")
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700307 private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>();
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700308 @GuardedBy("mLock")
309 private String mPrimaryStorageUuid;
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700310 @GuardedBy("mLock")
311 private boolean mForceAdoptable;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700312
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700313 /** Map from disk ID to latches */
314 @GuardedBy("mLock")
315 private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
316
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700317 @GuardedBy("mLock")
318 private IPackageMoveObserver mMoveCallback;
319 @GuardedBy("mLock")
320 private String mMoveTargetUuid;
321
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700322 private VolumeInfo findVolumeByIdOrThrow(String id) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700323 synchronized (mLock) {
324 final VolumeInfo vol = mVolumes.get(id);
325 if (vol != null) {
326 return vol;
327 }
328 }
329 throw new IllegalArgumentException("No volume found for ID " + id);
330 }
331
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700332 private String findVolumeIdForPathOrThrow(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700333 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700334 for (int i = 0; i < mVolumes.size(); i++) {
335 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700336 if (vol.path != null && path.startsWith(vol.path)) {
337 return vol.id;
Jeff Sharkey48877892015-03-18 11:27:19 -0700338 }
339 }
340 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700341 throw new IllegalArgumentException("No volume found for path " + path);
Jeff Sharkey48877892015-03-18 11:27:19 -0700342 }
343
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700344 private VolumeRecord findRecordForPath(String path) {
345 synchronized (mLock) {
346 for (int i = 0; i < mVolumes.size(); i++) {
347 final VolumeInfo vol = mVolumes.valueAt(i);
348 if (vol.path != null && path.startsWith(vol.path)) {
349 return mRecords.get(vol.fsUuid);
350 }
351 }
352 }
353 return null;
354 }
355
356 private String scrubPath(String path) {
357 if (path.startsWith(Environment.getDataDirectory().getAbsolutePath())) {
358 return "internal";
359 }
360 final VolumeRecord rec = findRecordForPath(path);
361 if (rec == null || rec.createdMillis == 0) {
362 return "unknown";
363 } else {
364 return "ext:" + (int) ((System.currentTimeMillis() - rec.createdMillis)
365 / DateUtils.WEEK_IN_MILLIS) + "w";
366 }
367 }
368
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700369 private @Nullable VolumeInfo findStorageForUuid(String volumeUuid) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700370 final StorageManager storage = mContext.getSystemService(StorageManager.class);
371 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700372 return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL);
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700373 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
374 return storage.getPrimaryPhysicalVolume();
375 } else {
376 return storage.findEmulatedForPrivate(storage.findVolumeByUuid(volumeUuid));
377 }
378 }
379
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700380 private boolean shouldBenchmark() {
381 final long benchInterval = Settings.Global.getLong(mContext.getContentResolver(),
382 Settings.Global.STORAGE_BENCHMARK_INTERVAL, DateUtils.WEEK_IN_MILLIS);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700383 if (benchInterval == -1) {
384 return false;
385 } else if (benchInterval == 0) {
386 return true;
387 }
388
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700389 synchronized (mLock) {
390 for (int i = 0; i < mVolumes.size(); i++) {
391 final VolumeInfo vol = mVolumes.valueAt(i);
392 final VolumeRecord rec = mRecords.get(vol.fsUuid);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700393 if (vol.isMountedWritable() && rec != null) {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700394 final long benchAge = System.currentTimeMillis() - rec.lastBenchMillis;
395 if (benchAge >= benchInterval) {
396 return true;
397 }
398 }
399 }
400 return false;
401 }
402 }
403
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700404 private CountDownLatch findOrCreateDiskScanLatch(String diskId) {
405 synchronized (mLock) {
406 CountDownLatch latch = mDiskScanLatches.get(diskId);
407 if (latch == null) {
408 latch = new CountDownLatch(1);
409 mDiskScanLatches.put(diskId, latch);
410 }
411 return latch;
412 }
413 }
414
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800415 private static String escapeNull(String arg) {
416 if (TextUtils.isEmpty(arg)) {
417 return "!";
418 } else {
419 if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
420 throw new IllegalArgumentException(arg);
421 }
422 return arg;
423 }
424 }
425
Paul Lawrence8e397362014-01-27 15:22:30 -0800426 /** List of crypto types.
427 * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
428 * corresponding commands in CommandListener.cpp */
429 public static final String[] CRYPTO_TYPES
430 = { "password", "default", "pattern", "pin" };
431
Brian Carlstrom7395a8a2014-04-28 22:11:01 -0700432 private final Context mContext;
Brian Carlstromdfad99a2014-05-07 15:21:14 -0700433 private final NativeDaemonConnector mConnector;
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700434 private final NativeDaemonConnector mCryptConnector;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700435
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700436 private volatile boolean mSystemReady = false;
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900437 private volatile boolean mBootCompleted = false;
Jeff Sharkey48877892015-03-18 11:27:19 -0700438 private volatile boolean mDaemonConnected = false;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700439
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700440 private PackageManagerService mPms;
441
442 private final Callbacks mCallbacks;
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700443 private final LockPatternUtils mLockPatternUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -0700444
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700445 // Two connectors - mConnector & mCryptConnector
446 private final CountDownLatch mConnectedSignal = new CountDownLatch(2);
Jeff Sharkey0be607c2012-11-14 14:39:19 -0800447 private final CountDownLatch mAsecsScanned = new CountDownLatch(1);
Jeff Sharkey48877892015-03-18 11:27:19 -0700448
449 private final Object mUnmountLock = new Object();
450 @GuardedBy("mUnmountLock")
451 private CountDownLatch mUnmountSignal;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800452
San Mehat6cdd9c02010-02-09 14:45:20 -0800453 /**
454 * Private hash of currently mounted secure containers.
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800455 * Used as a lock in methods to manipulate secure containers.
San Mehat6cdd9c02010-02-09 14:45:20 -0800456 */
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800457 final private HashSet<String> mAsecMountSet = new HashSet<String>();
San Mehat6cdd9c02010-02-09 14:45:20 -0800458
Kenny Root02c87302010-07-01 08:10:18 -0700459 /**
Kenny Root3b1abba2010-10-13 15:00:07 -0700460 * The size of the crypto algorithm key in bits for OBB files. Currently
461 * Twofish is used which takes 128-bit keys.
462 */
463 private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
464
465 /**
466 * The number of times to run SHA1 in the PBKDF2 function for OBB files.
467 * 1024 is reasonably secure and not too slow.
468 */
469 private static final int PBKDF2_HASH_ROUNDS = 1024;
470
471 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700472 * Mounted OBB tracking information. Used to track the current state of all
473 * OBBs.
Kenny Root02c87302010-07-01 08:10:18 -0700474 */
Kenny Root735de3b2010-09-30 14:11:39 -0700475 final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700476
477 /** Map from raw paths to {@link ObbState}. */
Kenny Roota02b8b02010-08-05 16:14:17 -0700478 final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
479
Svet Ganov6ee871e2015-07-10 14:29:33 -0700480 // Not guarded by a lock.
481 private final MountServiceInternalImpl mMountServiceInternal = new MountServiceInternalImpl();
482
Kenny Roota02b8b02010-08-05 16:14:17 -0700483 class ObbState implements IBinder.DeathRecipient {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700484 public ObbState(String rawPath, String canonicalPath, int callingUid,
485 IObbActionListener token, int nonce) {
486 this.rawPath = rawPath;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700487 this.canonicalPath = canonicalPath;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700488
489 this.ownerGid = UserHandle.getSharedAppGid(callingUid);
Kenny Rootaf9d6672010-10-08 09:21:39 -0700490 this.token = token;
491 this.nonce = nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700492 }
493
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700494 final String rawPath;
495 final String canonicalPath;
Kenny Roota02b8b02010-08-05 16:14:17 -0700496
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700497 final int ownerGid;
Kenny Roota02b8b02010-08-05 16:14:17 -0700498
Kenny Rootaf9d6672010-10-08 09:21:39 -0700499 // Token of remote Binder caller
500 final IObbActionListener token;
501
502 // Identifier to pass back to the token
503 final int nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700504
Kenny Root735de3b2010-09-30 14:11:39 -0700505 public IBinder getBinder() {
506 return token.asBinder();
507 }
508
Kenny Roota02b8b02010-08-05 16:14:17 -0700509 @Override
510 public void binderDied() {
511 ObbAction action = new UnmountObbAction(this, true);
512 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root735de3b2010-09-30 14:11:39 -0700513 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700514
Kenny Root5919ac62010-10-05 09:49:40 -0700515 public void link() throws RemoteException {
516 getBinder().linkToDeath(this, 0);
517 }
518
519 public void unlink() {
Kenny Root735de3b2010-09-30 14:11:39 -0700520 getBinder().unlinkToDeath(this, 0);
Kenny Roota02b8b02010-08-05 16:14:17 -0700521 }
Kenny Root38cf8862010-09-26 14:18:51 -0700522
523 @Override
524 public String toString() {
525 StringBuilder sb = new StringBuilder("ObbState{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700526 sb.append("rawPath=").append(rawPath);
527 sb.append(",canonicalPath=").append(canonicalPath);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700528 sb.append(",ownerGid=").append(ownerGid);
529 sb.append(",token=").append(token);
530 sb.append(",binder=").append(getBinder());
Kenny Root38cf8862010-09-26 14:18:51 -0700531 sb.append('}');
532 return sb.toString();
533 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700534 }
535
536 // OBB Action Handler
537 final private ObbActionHandler mObbActionHandler;
538
539 // OBB action handler messages
540 private static final int OBB_RUN_ACTION = 1;
541 private static final int OBB_MCS_BOUND = 2;
542 private static final int OBB_MCS_UNBIND = 3;
543 private static final int OBB_MCS_RECONNECT = 4;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700544 private static final int OBB_FLUSH_MOUNT_STATE = 5;
Kenny Roota02b8b02010-08-05 16:14:17 -0700545
546 /*
547 * Default Container Service information
548 */
549 static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
550 "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
551
552 final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
553
554 class DefaultContainerConnection implements ServiceConnection {
Jeff Sharkey48877892015-03-18 11:27:19 -0700555 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700556 public void onServiceConnected(ComponentName name, IBinder service) {
557 if (DEBUG_OBB)
558 Slog.i(TAG, "onServiceConnected");
559 IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
560 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
561 }
562
Jeff Sharkey48877892015-03-18 11:27:19 -0700563 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700564 public void onServiceDisconnected(ComponentName name) {
565 if (DEBUG_OBB)
566 Slog.i(TAG, "onServiceDisconnected");
567 }
568 };
569
570 // Used in the ObbActionHandler
571 private IMediaContainerService mContainerService = null;
Kenny Root02c87302010-07-01 08:10:18 -0700572
Christopher Tate7265abe2014-11-21 13:54:45 -0800573 // Last fstrim operation tracking
574 private static final String LAST_FSTRIM_FILE = "last-fstrim";
575 private final File mLastMaintenanceFile;
576 private long mLastMaintenance;
577
Kenny Root02c87302010-07-01 08:10:18 -0700578 // Handler messages
Jeff Sharkey48877892015-03-18 11:27:19 -0700579 private static final int H_SYSTEM_READY = 1;
580 private static final int H_DAEMON_CONNECTED = 2;
581 private static final int H_SHUTDOWN = 3;
582 private static final int H_FSTRIM = 4;
583 private static final int H_VOLUME_MOUNT = 5;
584 private static final int H_VOLUME_BROADCAST = 6;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700585 private static final int H_INTERNAL_BROADCAST = 7;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700586 private static final int H_VOLUME_UNMOUNT = 8;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800587 private static final int H_PARTITION_FORGET = 9;
588 private static final int H_RESET = 10;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800589
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400590 class MountServiceHandler extends Handler {
Jeff Sharkey48877892015-03-18 11:27:19 -0700591 public MountServiceHandler(Looper looper) {
592 super(looper);
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400593 }
594
Jason parks5af0b912010-11-29 09:05:25 -0600595 @Override
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800596 public void handleMessage(Message msg) {
597 switch (msg.what) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700598 case H_SYSTEM_READY: {
Jeff Sharkey48877892015-03-18 11:27:19 -0700599 handleSystemReady();
600 break;
601 }
602 case H_DAEMON_CONNECTED: {
603 handleDaemonConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700604 break;
605 }
Christopher Tated417d622013-08-19 16:14:25 -0700606 case H_FSTRIM: {
Jeff Sharkey1783f142015-04-17 10:52:51 -0700607 if (!isReady()) {
608 Slog.i(TAG, "fstrim requested, but no daemon connection yet; trying again");
Christopher Tate7618db12015-04-28 16:32:55 -0700609 sendMessageDelayed(obtainMessage(H_FSTRIM, msg.obj),
610 DateUtils.SECOND_IN_MILLIS);
611 break;
Jeff Sharkey1783f142015-04-17 10:52:51 -0700612 }
613
Christopher Tated417d622013-08-19 16:14:25 -0700614 Slog.i(TAG, "Running fstrim idle maintenance");
Christopher Tate7265abe2014-11-21 13:54:45 -0800615
616 // Remember when we kicked it off
617 try {
618 mLastMaintenance = System.currentTimeMillis();
619 mLastMaintenanceFile.setLastModified(mLastMaintenance);
620 } catch (Exception e) {
621 Slog.e(TAG, "Unable to record last fstrim!");
622 }
623
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700624 final boolean shouldBenchmark = shouldBenchmark();
Christopher Tated417d622013-08-19 16:14:25 -0700625 try {
626 // This method must be run on the main (handler) thread,
627 // so it is safe to directly call into vold.
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700628 mConnector.execute("fstrim", shouldBenchmark ? "dotrimbench" : "dotrim");
Christopher Tated417d622013-08-19 16:14:25 -0700629 } catch (NativeDaemonConnectorException ndce) {
630 Slog.e(TAG, "Failed to run fstrim!");
631 }
Christopher Tate7265abe2014-11-21 13:54:45 -0800632
Christopher Tated417d622013-08-19 16:14:25 -0700633 // invoke the completion callback, if any
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700634 // TODO: fstrim is non-blocking, so remove this useless callback
Christopher Tated417d622013-08-19 16:14:25 -0700635 Runnable callback = (Runnable) msg.obj;
636 if (callback != null) {
637 callback.run();
638 }
639 break;
640 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700641 case H_SHUTDOWN: {
642 final IMountShutdownObserver obs = (IMountShutdownObserver) msg.obj;
643 boolean success = false;
644 try {
645 success = mConnector.execute("volume", "shutdown").isClassOk();
646 } catch (NativeDaemonConnectorException ignored) {
647 }
648 if (obs != null) {
649 try {
650 obs.onShutDownComplete(success ? 0 : -1);
651 } catch (RemoteException ignored) {
652 }
653 }
654 break;
655 }
656 case H_VOLUME_MOUNT: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700657 final VolumeInfo vol = (VolumeInfo) msg.obj;
Jeff Sharkey2e606d72015-07-27 14:19:54 -0700658 if (isMountDisallowed(vol)) {
659 Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");
660 break;
661 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700662 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700663 mConnector.execute("volume", "mount", vol.id, vol.mountFlags,
664 vol.mountUserId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700665 } catch (NativeDaemonConnectorException ignored) {
666 }
667 break;
668 }
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700669 case H_VOLUME_UNMOUNT: {
670 final VolumeInfo vol = (VolumeInfo) msg.obj;
671 unmount(vol.getId());
672 break;
673 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700674 case H_VOLUME_BROADCAST: {
675 final StorageVolume userVol = (StorageVolume) msg.obj;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700676 final String envState = userVol.getState();
677 Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + envState + " to "
Jeff Sharkey48877892015-03-18 11:27:19 -0700678 + userVol.getOwner());
679
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700680 final String action = VolumeInfo.getBroadcastForEnvironment(envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700681 if (action != null) {
682 final Intent intent = new Intent(action,
683 Uri.fromFile(userVol.getPathFile()));
684 intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, userVol);
685 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
686 mContext.sendBroadcastAsUser(intent, userVol.getOwner());
687 }
688 break;
689 }
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700690 case H_INTERNAL_BROADCAST: {
691 // Internal broadcasts aimed at system components, not for
692 // third-party apps.
693 final Intent intent = (Intent) msg.obj;
694 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
695 android.Manifest.permission.WRITE_MEDIA_STORAGE);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800696 break;
697 }
698 case H_PARTITION_FORGET: {
699 final String partGuid = (String) msg.obj;
700 forgetPartition(partGuid);
701 break;
702 }
703 case H_RESET: {
704 resetIfReadyAndConnected();
705 break;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700706 }
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800707 }
708 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700709 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700710
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700711 private final Handler mHandler;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800712
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700713 private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
714 @Override
715 public void onReceive(Context context, Intent intent) {
716 final String action = intent.getAction();
717 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700718 Preconditions.checkArgument(userId >= 0);
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700719
720 try {
721 if (Intent.ACTION_USER_ADDED.equals(action)) {
722 final UserManager um = mContext.getSystemService(UserManager.class);
723 final int userSerialNumber = um.getUserSerialNumber(userId);
724 mConnector.execute("volume", "user_added", userId, userSerialNumber);
725 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700726 synchronized (mVolumes) {
727 final int size = mVolumes.size();
728 for (int i = 0; i < size; i++) {
729 final VolumeInfo vol = mVolumes.valueAt(i);
730 if (vol.mountUserId == userId) {
731 vol.mountUserId = UserHandle.USER_NULL;
732 mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
733 }
734 }
735 }
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700736 mConnector.execute("volume", "user_removed", userId);
737 }
738 } catch (NativeDaemonConnectorException e) {
739 Slog.w(TAG, "Failed to send user details to vold", e);
740 }
741 }
742 };
743
Jeff Sharkey56e62932015-03-21 20:41:00 -0700744 @Override
745 public void waitForAsecScan() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700746 waitForLatch(mAsecsScanned, "mAsecsScanned");
Kenny Root51a573c2012-05-17 13:30:28 -0700747 }
748
San Mehat207e5382010-02-04 20:46:54 -0800749 private void waitForReady() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700750 waitForLatch(mConnectedSignal, "mConnectedSignal");
Kenny Root51a573c2012-05-17 13:30:28 -0700751 }
752
Jeff Sharkey48877892015-03-18 11:27:19 -0700753 private void waitForLatch(CountDownLatch latch, String condition) {
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700754 try {
755 waitForLatch(latch, condition, -1);
756 } catch (TimeoutException ignored) {
757 }
758 }
759
760 private void waitForLatch(CountDownLatch latch, String condition, long timeoutMillis)
761 throws TimeoutException {
762 final long startMillis = SystemClock.elapsedRealtime();
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700763 while (true) {
Kenny Root51a573c2012-05-17 13:30:28 -0700764 try {
765 if (latch.await(5000, TimeUnit.MILLISECONDS)) {
San Mehat207e5382010-02-04 20:46:54 -0800766 return;
Kenny Root51a573c2012-05-17 13:30:28 -0700767 } else {
768 Slog.w(TAG, "Thread " + Thread.currentThread().getName()
Jeff Sharkey48877892015-03-18 11:27:19 -0700769 + " still waiting for " + condition + "...");
San Mehat207e5382010-02-04 20:46:54 -0800770 }
Kenny Root51a573c2012-05-17 13:30:28 -0700771 } catch (InterruptedException e) {
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700772 Slog.w(TAG, "Interrupt while waiting for " + condition);
San Mehat207e5382010-02-04 20:46:54 -0800773 }
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700774 if (timeoutMillis > 0 && SystemClock.elapsedRealtime() > startMillis + timeoutMillis) {
775 throw new TimeoutException("Thread " + Thread.currentThread().getName()
776 + " gave up waiting for " + condition + " after " + timeoutMillis + "ms");
777 }
San Mehat207e5382010-02-04 20:46:54 -0800778 }
San Mehat1f6301e2010-01-07 22:40:27 -0800779 }
Kenny Root02c87302010-07-01 08:10:18 -0700780
Paul Lawrence945490c2014-03-27 16:37:28 +0000781 private boolean isReady() {
782 try {
783 return mConnectedSignal.await(0, TimeUnit.MILLISECONDS);
784 } catch (InterruptedException e) {
785 return false;
786 }
787 }
788
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700789 private void handleSystemReady() {
Jeff Sharkey8924e872015-11-30 12:52:10 -0700790 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800791 resetIfReadyAndConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700792
Jeff Sharkey48877892015-03-18 11:27:19 -0700793 // Start scheduling nominally-daily fstrim operations
Christopher Tate115afda2014-06-06 19:06:26 -0700794 MountServiceIdler.scheduleIdlePass(mContext);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700795 }
796
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700797 /**
798 * MediaProvider has a ton of code that makes assumptions about storage
799 * paths never changing, so we outright kill them to pick up new state.
800 */
801 @Deprecated
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700802 private void killMediaProvider(List<UserInfo> users) {
803 if (users == null) return;
804
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700805 final long token = Binder.clearCallingIdentity();
806 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700807 for (UserInfo user : users) {
808 // System user does not have media provider, so skip.
809 if (user.isSystemOnly()) continue;
810
Jeff Sharkey2a9e3f82015-12-18 10:57:58 -0700811 final ProviderInfo provider = mPms.resolveContentProvider(MediaStore.AUTHORITY,
812 PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.id);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700813 if (provider != null) {
814 final IActivityManager am = ActivityManagerNative.getDefault();
815 try {
816 am.killApplicationWithAppId(provider.applicationInfo.packageName,
817 UserHandle.getAppId(provider.applicationInfo.uid), "vold reset");
818 // We only need to run this once. It will kill all users' media processes.
819 break;
820 } catch (RemoteException e) {
821 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700822 }
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700823 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700824 } finally {
825 Binder.restoreCallingIdentity(token);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700826 }
827 }
828
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800829 private void addInternalVolumeLocked() {
Amith Yamasania7892482015-08-07 11:09:05 -0700830 // Create a stub volume that represents internal storage
831 final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
832 VolumeInfo.TYPE_PRIVATE, null, null);
833 internal.state = VolumeInfo.STATE_MOUNTED;
834 internal.path = Environment.getDataDirectory().getAbsolutePath();
835 mVolumes.put(internal.id, internal);
836 }
837
Jeff Sharkey8924e872015-11-30 12:52:10 -0700838 private void initIfReadyAndConnected() {
839 Slog.d(TAG, "Thinking about init, mSystemReady=" + mSystemReady
840 + ", mDaemonConnected=" + mDaemonConnected);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700841 if (mSystemReady && mDaemonConnected
842 && !StorageManager.isNativeFileBasedEncryptionEnabled()) {
843 // When booting a device without native support, make sure that our
844 // user directories are locked or unlocked based on the current
845 // emulation status.
846 final boolean initLocked = StorageManager.isEmulatedFileBasedEncryptionEnabled();
847 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Jeff Sharkey8924e872015-11-30 12:52:10 -0700848 for (UserInfo user : users) {
849 try {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700850 if (initLocked) {
851 mCryptConnector.execute("cryptfs", "lock_user_key", user.id);
852 } else {
853 mCryptConnector.execute("cryptfs", "unlock_user_key", user.id,
854 user.serialNumber, "!");
855 }
Jeff Sharkey8924e872015-11-30 12:52:10 -0700856 } catch (NativeDaemonConnectorException e) {
857 Slog.w(TAG, "Failed to init vold", e);
858 }
859 }
860 }
861 }
862
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800863 private void resetIfReadyAndConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700864 Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
865 + ", mDaemonConnected=" + mDaemonConnected);
866 if (mSystemReady && mDaemonConnected) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800867 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700868 killMediaProvider(users);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700869
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700870 final int[] systemUnlockedUsers;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800871 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700872 systemUnlockedUsers = mSystemUnlockedUsers;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700873
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800874 mDisks.clear();
875 mVolumes.clear();
876
877 addInternalVolumeLocked();
878 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700879
Jeff Sharkey48877892015-03-18 11:27:19 -0700880 try {
881 mConnector.execute("volume", "reset");
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700882
883 // Tell vold about all existing and started users
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700884 for (UserInfo user : users) {
885 mConnector.execute("volume", "user_added", user.id, user.serialNumber);
886 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700887 for (int userId : systemUnlockedUsers) {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700888 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey50a05452015-04-29 11:24:52 -0700889 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700890 } catch (NativeDaemonConnectorException e) {
891 Slog.w(TAG, "Failed to reset vold", e);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700892 }
893 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700894 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700895
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700896 private void onUnlockUser(int userId) {
897 Slog.d(TAG, "onUnlockUser " + userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700898
899 // We purposefully block here to make sure that user-specific
900 // staging area is ready so it's ready for zygote-forked apps to
901 // bind mount against.
902 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700903 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700904 } catch (NativeDaemonConnectorException ignored) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700905 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700906
907 // Record user as started so newly mounted volumes kick off events
908 // correctly, then synthesize events for any already-mounted volumes.
909 synchronized (mVolumes) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700910 for (int i = 0; i < mVolumes.size(); i++) {
911 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey46349872015-07-28 10:49:47 -0700912 if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700913 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey48877892015-03-18 11:27:19 -0700914 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700915
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700916 final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
917 mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700918 }
919 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700920 mSystemUnlockedUsers = ArrayUtils.appendInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700921 }
922 }
923
924 private void onCleanupUser(int userId) {
925 Slog.d(TAG, "onCleanupUser " + userId);
926
927 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700928 mConnector.execute("volume", "user_stopped", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700929 } catch (NativeDaemonConnectorException ignored) {
930 }
931
932 synchronized (mVolumes) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700933 mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700934 }
935 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700936
Christopher Tated417d622013-08-19 16:14:25 -0700937 void runIdleMaintenance(Runnable callback) {
938 mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
939 }
940
Christopher Tate7265abe2014-11-21 13:54:45 -0800941 // Binder entry point for kicking off an immediate fstrim
942 @Override
943 public void runMaintenance() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700944 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Christopher Tate7265abe2014-11-21 13:54:45 -0800945 runIdleMaintenance(null);
946 }
947
948 @Override
949 public long lastMaintenance() {
950 return mLastMaintenance;
951 }
952
San Mehat4270e1e2010-01-29 05:32:19 -0800953 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800954 * Callback from NativeDaemonConnector
955 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700956 @Override
San Mehat4270e1e2010-01-29 05:32:19 -0800957 public void onDaemonConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700958 mDaemonConnected = true;
959 mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();
960 }
961
962 private void handleDaemonConnected() {
Jeff Sharkey8924e872015-11-30 12:52:10 -0700963 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800964 resetIfReadyAndConnected();
Jeff Sharkey48877892015-03-18 11:27:19 -0700965
San Mehat4270e1e2010-01-29 05:32:19 -0800966 /*
Jeff Sharkey48877892015-03-18 11:27:19 -0700967 * Now that we've done our initialization, release
968 * the hounds!
San Mehat4270e1e2010-01-29 05:32:19 -0800969 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700970 mConnectedSignal.countDown();
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700971 if (mConnectedSignal.getCount() != 0) {
972 // More daemons need to connect
973 return;
974 }
Mike Lockwood7fa24aa2011-03-23 14:52:34 -0400975
Jeff Sharkey48877892015-03-18 11:27:19 -0700976 // On an encrypted device we can't see system properties yet, so pull
977 // the system locale out of the mount service.
978 if ("".equals(SystemProperties.get("vold.encrypt_progress"))) {
979 copyLocaleFromMountService();
980 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700981
Jeff Sharkey48877892015-03-18 11:27:19 -0700982 // Let package manager load internal ASECs.
983 mPms.scanAvailableAsecs();
Mike Lockwood7fa24aa2011-03-23 14:52:34 -0400984
Jeff Sharkey48877892015-03-18 11:27:19 -0700985 // Notify people waiting for ASECs to be scanned that it's done.
986 mAsecsScanned.countDown();
San Mehat4270e1e2010-01-29 05:32:19 -0800987 }
988
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700989 private void copyLocaleFromMountService() {
990 String systemLocale;
991 try {
992 systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
993 } catch (RemoteException e) {
994 return;
995 }
996 if (TextUtils.isEmpty(systemLocale)) {
997 return;
998 }
999
1000 Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
1001 Locale locale = Locale.forLanguageTag(systemLocale);
1002 Configuration config = new Configuration();
1003 config.setLocale(locale);
1004 try {
1005 ActivityManagerNative.getDefault().updateConfiguration(config);
1006 } catch (RemoteException e) {
1007 Slog.e(TAG, "Error setting system locale from mount service", e);
1008 }
Elliott Hughes9c33f282014-10-13 12:39:56 -07001009
1010 // Temporary workaround for http://b/17945169.
1011 Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
Narayan Kamathd30dbb82015-01-15 14:48:15 +00001012 SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001013 }
1014
San Mehat4270e1e2010-01-29 05:32:19 -08001015 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001016 * Callback from NativeDaemonConnector
1017 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001018 @Override
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001019 public boolean onCheckHoldWakeLock(int code) {
1020 return false;
1021 }
1022
1023 /**
1024 * Callback from NativeDaemonConnector
1025 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001026 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001027 public boolean onEvent(int code, String raw, String[] cooked) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001028 synchronized (mLock) {
1029 return onEventLocked(code, raw, cooked);
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -08001030 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001031 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001032
Jeff Sharkey48877892015-03-18 11:27:19 -07001033 private boolean onEventLocked(int code, String raw, String[] cooked) {
1034 switch (code) {
1035 case VoldResponseCode.DISK_CREATED: {
1036 if (cooked.length != 3) break;
1037 final String id = cooked[1];
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001038 int flags = Integer.parseInt(cooked[2]);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001039 if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false)
1040 || mForceAdoptable) {
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001041 flags |= DiskInfo.FLAG_ADOPTABLE;
1042 }
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001043 mDisks.put(id, new DiskInfo(id, flags));
Jeff Sharkey48877892015-03-18 11:27:19 -07001044 break;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001045 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001046 case VoldResponseCode.DISK_SIZE_CHANGED: {
1047 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001048 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001049 if (disk != null) {
1050 disk.size = Long.parseLong(cooked[2]);
San Mehat4270e1e2010-01-29 05:32:19 -08001051 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001052 break;
1053 }
1054 case VoldResponseCode.DISK_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001055 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001056 if (disk != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001057 final StringBuilder builder = new StringBuilder();
1058 for (int i = 2; i < cooked.length; i++) {
1059 builder.append(cooked[i]).append(' ');
1060 }
1061 disk.label = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001062 }
1063 break;
1064 }
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001065 case VoldResponseCode.DISK_SCANNED: {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001066 if (cooked.length != 2) break;
1067 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001068 if (disk != null) {
1069 onDiskScannedLocked(disk);
1070 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -07001071 break;
1072 }
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001073 case VoldResponseCode.DISK_SYS_PATH_CHANGED: {
1074 if (cooked.length != 3) break;
1075 final DiskInfo disk = mDisks.get(cooked[1]);
1076 if (disk != null) {
1077 disk.sysPath = cooked[2];
1078 }
1079 break;
1080 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001081 case VoldResponseCode.DISK_DESTROYED: {
1082 if (cooked.length != 2) break;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07001083 final DiskInfo disk = mDisks.remove(cooked[1]);
1084 if (disk != null) {
1085 mCallbacks.notifyDiskDestroyed(disk);
1086 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001087 break;
1088 }
San Mehat4270e1e2010-01-29 05:32:19 -08001089
Jeff Sharkey48877892015-03-18 11:27:19 -07001090 case VoldResponseCode.VOLUME_CREATED: {
Jeff Sharkey48877892015-03-18 11:27:19 -07001091 final String id = cooked[1];
1092 final int type = Integer.parseInt(cooked[2]);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001093 final String diskId = TextUtils.nullIfEmpty(cooked[3]);
1094 final String partGuid = TextUtils.nullIfEmpty(cooked[4]);
1095
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001096 final DiskInfo disk = mDisks.get(diskId);
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07001097 final VolumeInfo vol = new VolumeInfo(id, type, disk, partGuid);
Jeff Sharkey48877892015-03-18 11:27:19 -07001098 mVolumes.put(id, vol);
1099 onVolumeCreatedLocked(vol);
1100 break;
1101 }
1102 case VoldResponseCode.VOLUME_STATE_CHANGED: {
1103 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001104 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001105 if (vol != null) {
1106 final int oldState = vol.state;
1107 final int newState = Integer.parseInt(cooked[2]);
1108 vol.state = newState;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001109 onVolumeStateChangedLocked(vol, oldState, newState);
Jeff Sharkey48877892015-03-18 11:27:19 -07001110 }
1111 break;
1112 }
1113 case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: {
1114 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001115 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001116 if (vol != null) {
1117 vol.fsType = cooked[2];
1118 }
1119 break;
1120 }
1121 case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
1122 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001123 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001124 if (vol != null) {
1125 vol.fsUuid = cooked[2];
1126 }
1127 break;
1128 }
1129 case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001130 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001131 if (vol != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001132 final StringBuilder builder = new StringBuilder();
1133 for (int i = 2; i < cooked.length; i++) {
1134 builder.append(cooked[i]).append(' ');
1135 }
1136 vol.fsLabel = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001137 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001138 // TODO: notify listeners that label changed
Jeff Sharkey48877892015-03-18 11:27:19 -07001139 break;
1140 }
1141 case VoldResponseCode.VOLUME_PATH_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.path = cooked[2];
1146 }
1147 break;
1148 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001149 case VoldResponseCode.VOLUME_INTERNAL_PATH_CHANGED: {
1150 if (cooked.length != 3) break;
1151 final VolumeInfo vol = mVolumes.get(cooked[1]);
1152 if (vol != null) {
1153 vol.internalPath = cooked[2];
1154 }
1155 break;
1156 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001157 case VoldResponseCode.VOLUME_DESTROYED: {
1158 if (cooked.length != 2) break;
1159 mVolumes.remove(cooked[1]);
1160 break;
1161 }
San Mehat4270e1e2010-01-29 05:32:19 -08001162
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001163 case VoldResponseCode.MOVE_STATUS: {
1164 final int status = Integer.parseInt(cooked[1]);
1165 onMoveStatusLocked(status);
1166 break;
1167 }
Jeff Sharkey9756d752015-05-14 21:07:42 -07001168 case VoldResponseCode.BENCHMARK_RESULT: {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001169 if (cooked.length != 7) break;
1170 final String path = cooked[1];
1171 final String ident = cooked[2];
1172 final long create = Long.parseLong(cooked[3]);
1173 final long drop = Long.parseLong(cooked[4]);
1174 final long run = Long.parseLong(cooked[5]);
1175 final long destroy = Long.parseLong(cooked[6]);
1176
Jeff Sharkey9756d752015-05-14 21:07:42 -07001177 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001178 dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
1179 + " " + ident + " " + create + " " + run + " " + destroy);
1180
1181 final VolumeRecord rec = findRecordForPath(path);
1182 if (rec != null) {
1183 rec.lastBenchMillis = System.currentTimeMillis();
1184 writeSettingsLocked();
1185 }
1186
1187 break;
1188 }
1189 case VoldResponseCode.TRIM_RESULT: {
1190 if (cooked.length != 4) break;
1191 final String path = cooked[1];
1192 final long bytes = Long.parseLong(cooked[2]);
1193 final long time = Long.parseLong(cooked[3]);
1194
1195 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
1196 dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path)
1197 + " " + bytes + " " + time);
1198
1199 final VolumeRecord rec = findRecordForPath(path);
1200 if (rec != null) {
1201 rec.lastTrimMillis = System.currentTimeMillis();
1202 writeSettingsLocked();
1203 }
1204
Jeff Sharkey9756d752015-05-14 21:07:42 -07001205 break;
1206 }
1207
Jeff Sharkey48877892015-03-18 11:27:19 -07001208 default: {
1209 Slog.d(TAG, "Unhandled vold event " + code);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001210 }
San Mehat4270e1e2010-01-29 05:32:19 -08001211 }
1212
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001213 return true;
San Mehat4270e1e2010-01-29 05:32:19 -08001214 }
1215
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001216 private void onDiskScannedLocked(DiskInfo disk) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001217 int volumeCount = 0;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001218 for (int i = 0; i < mVolumes.size(); i++) {
1219 final VolumeInfo vol = mVolumes.valueAt(i);
1220 if (Objects.equals(disk.id, vol.getDiskId())) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001221 volumeCount++;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001222 }
1223 }
1224
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001225 final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
1226 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1227 intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
1228 intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001229 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001230
1231 final CountDownLatch latch = mDiskScanLatches.remove(disk.id);
1232 if (latch != null) {
1233 latch.countDown();
1234 }
1235
Jeff Sharkeyf5a6bd72015-05-19 14:42:38 -07001236 disk.volumeCount = volumeCount;
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001237 mCallbacks.notifyDiskScanned(disk, volumeCount);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001238 }
1239
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001240 private void onVolumeCreatedLocked(VolumeInfo vol) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001241 if (vol.type == VolumeInfo.TYPE_EMULATED) {
1242 final StorageManager storage = mContext.getSystemService(StorageManager.class);
1243 final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
1244
1245 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
1246 && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
1247 Slog.v(TAG, "Found primary storage at " + vol);
1248 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1249 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1250 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1251
1252 } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
1253 Slog.v(TAG, "Found primary storage at " + vol);
1254 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1255 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1256 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1257 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001258
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001259 } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001260 // TODO: only look at first public partition
1261 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1262 && vol.disk.isDefaultPrimary()) {
1263 Slog.v(TAG, "Found primary storage at " + vol);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001264 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1265 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
San Mehat4270e1e2010-01-29 05:32:19 -08001266 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001267
1268 // Adoptable public disks are visible to apps, since they meet
1269 // public API requirement of being in a stable location.
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001270 if (vol.disk.isAdoptable()) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001271 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1272 }
1273
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07001274 vol.mountUserId = ActivityManager.getCurrentUser();
Jeff Sharkey48877892015-03-18 11:27:19 -07001275 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001276
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001277 } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1278 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1279
San Mehat4270e1e2010-01-29 05:32:19 -08001280 } else {
Jeff Sharkey48877892015-03-18 11:27:19 -07001281 Slog.d(TAG, "Skipping automatic mounting of " + vol);
San Mehat4270e1e2010-01-29 05:32:19 -08001282 }
1283 }
1284
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001285 private boolean isBroadcastWorthy(VolumeInfo vol) {
1286 switch (vol.getType()) {
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001287 case VolumeInfo.TYPE_PRIVATE:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001288 case VolumeInfo.TYPE_PUBLIC:
1289 case VolumeInfo.TYPE_EMULATED:
1290 break;
1291 default:
1292 return false;
1293 }
1294
1295 switch (vol.getState()) {
1296 case VolumeInfo.STATE_MOUNTED:
1297 case VolumeInfo.STATE_MOUNTED_READ_ONLY:
1298 case VolumeInfo.STATE_EJECTING:
1299 case VolumeInfo.STATE_UNMOUNTED:
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001300 case VolumeInfo.STATE_UNMOUNTABLE:
Tony Mantlerf0d71052015-06-24 11:45:25 -07001301 case VolumeInfo.STATE_BAD_REMOVAL:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001302 break;
1303 default:
1304 return false;
1305 }
1306
1307 return true;
1308 }
1309
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001310 private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001311 // Remember that we saw this volume so we're ready to accept user
1312 // metadata, or so we can annoy them when a private volume is ejected
1313 if (vol.isMountedReadable() && !TextUtils.isEmpty(vol.fsUuid)) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001314 VolumeRecord rec = mRecords.get(vol.fsUuid);
1315 if (rec == null) {
1316 rec = new VolumeRecord(vol.type, vol.fsUuid);
1317 rec.partGuid = vol.partGuid;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001318 rec.createdMillis = System.currentTimeMillis();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001319 if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1320 rec.nickname = vol.disk.getDescription();
1321 }
1322 mRecords.put(rec.fsUuid, rec);
1323 writeSettingsLocked();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001324 } else {
1325 // Handle upgrade case where we didn't store partition GUID
1326 if (TextUtils.isEmpty(rec.partGuid)) {
1327 rec.partGuid = vol.partGuid;
1328 writeSettingsLocked();
1329 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001330 }
1331 }
1332
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001333 mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
1334
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001335 // Do not broadcast before boot has completed to avoid launching the
1336 // processes that receive the intent unnecessarily.
1337 if (mBootCompleted && isBroadcastWorthy(vol)) {
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001338 final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001339 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
1340 intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
Tony Mantlerf0d71052015-06-24 11:45:25 -07001341 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001342 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001343 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001344 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001345
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001346 final String oldStateEnv = VolumeInfo.getEnvironmentForState(oldState);
1347 final String newStateEnv = VolumeInfo.getEnvironmentForState(newState);
Emily Bernier92aa5a22014-07-07 10:11:48 -04001348
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001349 if (!Objects.equals(oldStateEnv, newStateEnv)) {
1350 // Kick state changed event towards all started users. Any users
1351 // started after this point will trigger additional
1352 // user-specific broadcasts.
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001353 for (int userId : mSystemUnlockedUsers) {
Jeff Sharkey46349872015-07-28 10:49:47 -07001354 if (vol.isVisibleForRead(userId)) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001355 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001356 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey48877892015-03-18 11:27:19 -07001357
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001358 mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
1359 newStateEnv);
San Mehat4270e1e2010-01-29 05:32:19 -08001360 }
1361 }
1362 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001363
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001364 if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.state == VolumeInfo.STATE_EJECTING) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001365 // TODO: this should eventually be handled by new ObbVolume state changes
1366 /*
1367 * Some OBBs might have been unmounted when this volume was
1368 * unmounted, so send a message to the handler to let it know to
1369 * remove those from the list of mounted OBBS.
1370 */
1371 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
1372 OBB_FLUSH_MOUNT_STATE, vol.path));
1373 }
San Mehat4270e1e2010-01-29 05:32:19 -08001374 }
1375
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001376 private void onMoveStatusLocked(int status) {
1377 if (mMoveCallback == null) {
1378 Slog.w(TAG, "Odd, status but no move requested");
1379 return;
1380 }
1381
1382 // TODO: estimate remaining time
1383 try {
Jeff Sharkey50a05452015-04-29 11:24:52 -07001384 mMoveCallback.onStatusChanged(-1, status, -1);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001385 } catch (RemoteException ignored) {
1386 }
1387
1388 // We've finished copying and we're about to clean up old data, so
1389 // remember that move was successful if we get rebooted
1390 if (status == MOVE_STATUS_COPY_FINISHED) {
1391 Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
1392
1393 mPrimaryStorageUuid = mMoveTargetUuid;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001394 writeSettingsLocked();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001395 }
1396
1397 if (PackageManager.isMoveStatusFinished(status)) {
1398 Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status);
1399
1400 mMoveCallback = null;
1401 mMoveTargetUuid = null;
1402 }
1403 }
1404
Jeff Sharkey48877892015-03-18 11:27:19 -07001405 private void enforcePermission(String perm) {
1406 mContext.enforceCallingOrSelfPermission(perm, perm);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001407 }
1408
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001409 /**
1410 * Decide if volume is mountable per device policies.
1411 */
1412 private boolean isMountDisallowed(VolumeInfo vol) {
1413 if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
1414 final UserManager userManager = mContext.getSystemService(UserManager.class);
1415 return userManager.hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
1416 Binder.getCallingUserHandle());
1417 } else {
1418 return false;
Emily Bernier92aa5a22014-07-07 10:11:48 -04001419 }
1420 }
1421
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001422 private void enforceAdminUser() {
1423 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1424 final int callingUserId = UserHandle.getCallingUserId();
1425 boolean isAdmin;
1426 long token = Binder.clearCallingIdentity();
1427 try {
1428 isAdmin = um.getUserInfo(callingUserId).isAdmin();
1429 } finally {
1430 Binder.restoreCallingIdentity(token);
1431 }
1432 if (!isAdmin) {
1433 throw new SecurityException("Only admin users can adopt sd cards");
1434 }
1435 }
1436
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001437 /**
San Mehat207e5382010-02-04 20:46:54 -08001438 * Constructs a new MountService instance
1439 *
1440 * @param context Binder context for this service
1441 */
1442 public MountService(Context context) {
Christopher Tated417d622013-08-19 16:14:25 -07001443 sSelf = this;
1444
San Mehat207e5382010-02-04 20:46:54 -08001445 mContext = context;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001446 mCallbacks = new Callbacks(FgThread.get().getLooper());
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001447 mLockPatternUtils = new LockPatternUtils(mContext);
San Mehat207e5382010-02-04 20:46:54 -08001448
San Mehat207e5382010-02-04 20:46:54 -08001449 // XXX: This will go away soon in favor of IMountServiceObserver
1450 mPms = (PackageManagerService) ServiceManager.getService("package");
1451
Dianne Hackbornefa92b22013-05-03 14:11:43 -07001452 HandlerThread hthread = new HandlerThread(TAG);
1453 hthread.start();
1454 mHandler = new MountServiceHandler(hthread.getLooper());
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001455
Kenny Roota02b8b02010-08-05 16:14:17 -07001456 // Add OBB Action Handler to MountService thread.
Dianne Hackborn8d044e82013-04-30 17:24:15 -07001457 mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
Kenny Roota02b8b02010-08-05 16:14:17 -07001458
Christopher Tate7265abe2014-11-21 13:54:45 -08001459 // Initialize the last-fstrim tracking if necessary
1460 File dataDir = Environment.getDataDirectory();
1461 File systemDir = new File(dataDir, "system");
1462 mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
1463 if (!mLastMaintenanceFile.exists()) {
1464 // Not setting mLastMaintenance here means that we will force an
1465 // fstrim during reboot following the OTA that installs this code.
1466 try {
1467 (new FileOutputStream(mLastMaintenanceFile)).close();
1468 } catch (IOException e) {
1469 Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
1470 }
1471 } else {
1472 mLastMaintenance = mLastMaintenanceFile.lastModified();
1473 }
1474
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001475 mSettingsFile = new AtomicFile(
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001476 new File(Environment.getSystemSecureDirectory(), "storage.xml"));
1477
1478 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001479 readSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001480 }
1481
Svet Ganov6ee871e2015-07-10 14:29:33 -07001482 LocalServices.addService(MountServiceInternal.class, mMountServiceInternal);
1483
Marco Nelissenc34ebce2010-02-18 13:39:41 -08001484 /*
Kenny Root305bcbf2010-09-03 07:56:38 -07001485 * Create the connection to vold with a maximum queue of twice the
1486 * amount of containers we'd ever expect to have. This keeps an
1487 * "asec list" from blocking a thread repeatedly.
1488 */
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001489
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001490 mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
1491 null);
Jeff Sharkey48877892015-03-18 11:27:19 -07001492 mConnector.setDebug(true);
Jeff Sharkey8948c012015-11-03 12:33:54 -08001493 mConnector.setWarnIfHeld(mLock);
Kenny Root51a573c2012-05-17 13:30:28 -07001494
Kenny Root305bcbf2010-09-03 07:56:38 -07001495 Thread thread = new Thread(mConnector, VOLD_TAG);
San Mehat207e5382010-02-04 20:46:54 -08001496 thread.start();
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07001497
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001498 // Reuse parameters from first connector since they are tested and safe
1499 mCryptConnector = new NativeDaemonConnector(this, "cryptd",
1500 MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
1501 mCryptConnector.setDebug(true);
1502
1503 Thread crypt_thread = new Thread(mCryptConnector, CRYPTD_TAG);
1504 crypt_thread.start();
1505
Jeff Sharkeybcd262d2015-06-10 09:41:17 -07001506 final IntentFilter userFilter = new IntentFilter();
1507 userFilter.addAction(Intent.ACTION_USER_ADDED);
1508 userFilter.addAction(Intent.ACTION_USER_REMOVED);
1509 mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
1510
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001511 synchronized (mLock) {
1512 addInternalVolumeLocked();
1513 }
Amith Yamasania7892482015-08-07 11:09:05 -07001514
Kenny Root07714d42011-08-17 17:49:28 -07001515 // Add ourself to the Watchdog monitors if enabled.
1516 if (WATCHDOG_ENABLE) {
1517 Watchdog.getInstance().addMonitor(this);
1518 }
San Mehat207e5382010-02-04 20:46:54 -08001519 }
1520
Jeff Sharkey56e62932015-03-21 20:41:00 -07001521 private void systemReady() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001522 mSystemReady = true;
1523 mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
1524 }
1525
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001526 private void bootCompleted() {
1527 mBootCompleted = true;
1528 }
1529
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001530 private String getDefaultPrimaryStorageUuid() {
1531 if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) {
1532 return StorageManager.UUID_PRIMARY_PHYSICAL;
1533 } else {
1534 return StorageManager.UUID_PRIVATE_INTERNAL;
1535 }
1536 }
1537
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001538 private void readSettingsLocked() {
1539 mRecords.clear();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001540 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001541 mForceAdoptable = false;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001542
1543 FileInputStream fis = null;
1544 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001545 fis = mSettingsFile.openRead();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001546 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001547 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001548
1549 int type;
1550 while ((type = in.next()) != END_DOCUMENT) {
1551 if (type == START_TAG) {
1552 final String tag = in.getName();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001553 if (TAG_VOLUMES.equals(tag)) {
1554 final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001555 final boolean primaryPhysical = SystemProperties.getBoolean(
1556 StorageManager.PROP_PRIMARY_PHYSICAL, false);
1557 final boolean validAttr = (version >= VERSION_FIX_PRIMARY)
1558 || (version >= VERSION_ADD_PRIMARY && !primaryPhysical);
1559 if (validAttr) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001560 mPrimaryStorageUuid = readStringAttribute(in,
1561 ATTR_PRIMARY_STORAGE_UUID);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001562 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001563 mForceAdoptable = readBooleanAttribute(in, ATTR_FORCE_ADOPTABLE, false);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001564
1565 } else if (TAG_VOLUME.equals(tag)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001566 final VolumeRecord rec = readVolumeRecord(in);
1567 mRecords.put(rec.fsUuid, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001568 }
1569 }
1570 }
1571 } catch (FileNotFoundException e) {
1572 // Missing metadata is okay, probably first boot
1573 } catch (IOException e) {
1574 Slog.wtf(TAG, "Failed reading metadata", e);
1575 } catch (XmlPullParserException e) {
1576 Slog.wtf(TAG, "Failed reading metadata", e);
1577 } finally {
1578 IoUtils.closeQuietly(fis);
1579 }
1580 }
1581
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001582 private void writeSettingsLocked() {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001583 FileOutputStream fos = null;
1584 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001585 fos = mSettingsFile.startWrite();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001586
1587 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001588 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001589 out.startDocument(null, true);
1590 out.startTag(null, TAG_VOLUMES);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001591 writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001592 writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001593 writeBooleanAttribute(out, ATTR_FORCE_ADOPTABLE, mForceAdoptable);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001594 final int size = mRecords.size();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001595 for (int i = 0; i < size; i++) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001596 final VolumeRecord rec = mRecords.valueAt(i);
1597 writeVolumeRecord(out, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001598 }
1599 out.endTag(null, TAG_VOLUMES);
1600 out.endDocument();
1601
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001602 mSettingsFile.finishWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001603 } catch (IOException e) {
1604 if (fos != null) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001605 mSettingsFile.failWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001606 }
1607 }
1608 }
1609
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001610 public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
1611 final int type = readIntAttribute(in, ATTR_TYPE);
1612 final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
1613 final VolumeRecord meta = new VolumeRecord(type, fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001614 meta.partGuid = readStringAttribute(in, ATTR_PART_GUID);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001615 meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
1616 meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001617 meta.createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
1618 meta.lastTrimMillis = readLongAttribute(in, ATTR_LAST_TRIM_MILLIS);
1619 meta.lastBenchMillis = readLongAttribute(in, ATTR_LAST_BENCH_MILLIS);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001620 return meta;
1621 }
1622
1623 public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
1624 out.startTag(null, TAG_VOLUME);
1625 writeIntAttribute(out, ATTR_TYPE, rec.type);
1626 writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001627 writeStringAttribute(out, ATTR_PART_GUID, rec.partGuid);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001628 writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
1629 writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001630 writeLongAttribute(out, ATTR_CREATED_MILLIS, rec.createdMillis);
1631 writeLongAttribute(out, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
1632 writeLongAttribute(out, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001633 out.endTag(null, TAG_VOLUME);
1634 }
1635
San Mehat207e5382010-02-04 20:46:54 -08001636 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001637 * Exposed API calls below here
1638 */
1639
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001640 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001641 public void registerListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001642 mCallbacks.register(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001643 }
1644
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001645 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001646 public void unregisterListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001647 mCallbacks.unregister(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001648 }
1649
Jeff Sharkey48877892015-03-18 11:27:19 -07001650 @Override
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -08001651 public void shutdown(final IMountShutdownObserver observer) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001652 enforcePermission(android.Manifest.permission.SHUTDOWN);
San Mehat4270e1e2010-01-29 05:32:19 -08001653
San Mehata5078592010-03-25 09:36:54 -07001654 Slog.i(TAG, "Shutting down");
Jeff Sharkey48877892015-03-18 11:27:19 -07001655 mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001656 }
1657
Jeff Sharkey48877892015-03-18 11:27:19 -07001658 @Override
San Mehatb1043402010-02-05 08:26:50 -08001659 public boolean isUsbMassStorageConnected() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001660 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001661 }
1662
Jeff Sharkey48877892015-03-18 11:27:19 -07001663 @Override
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -08001664 public void setUsbMassStorageEnabled(boolean enable) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001665 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001666 }
1667
Jeff Sharkey48877892015-03-18 11:27:19 -07001668 @Override
San Mehatb1043402010-02-05 08:26:50 -08001669 public boolean isUsbMassStorageEnabled() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001670 throw new UnsupportedOperationException();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 }
Jason parks9ed98bc2011-01-17 09:58:35 -06001672
Jeff Sharkey48877892015-03-18 11:27:19 -07001673 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001674 public String getVolumeState(String mountPoint) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001675 throw new UnsupportedOperationException();
San Mehat7fd0fee2009-12-17 07:12:23 -08001676 }
1677
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001678 @Override
Kenny Roote1ff2142010-10-12 11:20:01 -07001679 public boolean isExternalStorageEmulated() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001680 throw new UnsupportedOperationException();
Kenny Roote1ff2142010-10-12 11:20:01 -07001681 }
1682
Jeff Sharkey48877892015-03-18 11:27:19 -07001683 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001684 public int mountVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001685 mount(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001686 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001687 }
1688
Jeff Sharkey48877892015-03-18 11:27:19 -07001689 @Override
Ben Komalo13c71972011-09-07 16:35:56 -07001690 public void unmountVolume(String path, boolean force, boolean removeEncryption) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001691 unmount(findVolumeIdForPathOrThrow(path));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 }
1693
Jeff Sharkey48877892015-03-18 11:27:19 -07001694 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001695 public int formatVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001696 format(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001697 return 0;
1698 }
1699
1700 @Override
1701 public void mount(String volId) {
1702 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1703 waitForReady();
1704
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001705 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001706 if (isMountDisallowed(vol)) {
1707 throw new SecurityException("Mounting " + volId + " restricted by policy");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001708 }
1709 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001710 mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001711 } catch (NativeDaemonConnectorException e) {
1712 throw e.rethrowAsParcelableException();
1713 }
1714 }
1715
1716 @Override
1717 public void unmount(String volId) {
1718 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1719 waitForReady();
1720
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001721 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001722
1723 // TODO: expand PMS to know about multiple volumes
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001724 if (vol.isPrimaryPhysical()) {
1725 final long ident = Binder.clearCallingIdentity();
1726 try {
1727 synchronized (mUnmountLock) {
1728 mUnmountSignal = new CountDownLatch(1);
1729 mPms.updateExternalMediaStatus(false, true);
1730 waitForLatch(mUnmountSignal, "mUnmountSignal");
1731 mUnmountSignal = null;
1732 }
1733 } finally {
1734 Binder.restoreCallingIdentity(ident);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001735 }
1736 }
1737
1738 try {
1739 mConnector.execute("volume", "unmount", vol.id);
1740 } catch (NativeDaemonConnectorException e) {
1741 throw e.rethrowAsParcelableException();
1742 }
1743 }
1744
1745 @Override
1746 public void format(String volId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001747 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -08001748 waitForReady();
San Mehat5b77dab2010-01-26 13:28:50 -08001749
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001750 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001751 try {
Jeff Sharkey4e83cc92015-05-27 14:38:39 -07001752 mConnector.execute("volume", "format", vol.id, "auto");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001753 } catch (NativeDaemonConnectorException e) {
1754 throw e.rethrowAsParcelableException();
Jeff Sharkey48877892015-03-18 11:27:19 -07001755 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001756 }
1757
1758 @Override
Jeff Sharkey9756d752015-05-14 21:07:42 -07001759 public long benchmark(String volId) {
1760 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1761 waitForReady();
1762
1763 try {
Jeff Sharkey14cbe522015-07-08 14:06:37 -07001764 // TODO: make benchmark async so we don't block other commands
1765 final NativeDaemonEvent res = mConnector.execute(3 * DateUtils.MINUTE_IN_MILLIS,
1766 "volume", "benchmark", volId);
Jeff Sharkey9756d752015-05-14 21:07:42 -07001767 return Long.parseLong(res.getMessage());
Todd Kennedy8101ee62015-06-23 13:35:28 -07001768 } catch (NativeDaemonTimeoutException e) {
1769 return Long.MAX_VALUE;
Jeff Sharkey9756d752015-05-14 21:07:42 -07001770 } catch (NativeDaemonConnectorException e) {
1771 throw e.rethrowAsParcelableException();
1772 }
1773 }
1774
1775 @Override
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001776 public void partitionPublic(String diskId) {
1777 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1778 waitForReady();
1779
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001780 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001781 try {
1782 mConnector.execute("volume", "partition", diskId, "public");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001783 waitForLatch(latch, "partitionPublic", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001784 } catch (NativeDaemonConnectorException e) {
1785 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001786 } catch (TimeoutException e) {
1787 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001788 }
1789 }
1790
1791 @Override
1792 public void partitionPrivate(String diskId) {
1793 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001794 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001795 waitForReady();
1796
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001797 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001798 try {
1799 mConnector.execute("volume", "partition", diskId, "private");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001800 waitForLatch(latch, "partitionPrivate", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001801 } catch (NativeDaemonConnectorException e) {
1802 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001803 } catch (TimeoutException e) {
1804 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001805 }
1806 }
1807
1808 @Override
1809 public void partitionMixed(String diskId, int ratio) {
1810 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001811 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001812 waitForReady();
1813
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001814 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001815 try {
1816 mConnector.execute("volume", "partition", diskId, "mixed", ratio);
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001817 waitForLatch(latch, "partitionMixed", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001818 } catch (NativeDaemonConnectorException e) {
1819 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001820 } catch (TimeoutException e) {
1821 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001822 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001823 }
1824
Jeff Sharkey48877892015-03-18 11:27:19 -07001825 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001826 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001827 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1828 waitForReady();
1829
Jeff Sharkey50a05452015-04-29 11:24:52 -07001830 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001831 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001832 final VolumeRecord rec = mRecords.get(fsUuid);
1833 rec.nickname = nickname;
Jeff Sharkey50a05452015-04-29 11:24:52 -07001834 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001835 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001836 }
1837 }
1838
1839 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001840 public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001841 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1842 waitForReady();
1843
Jeff Sharkey50a05452015-04-29 11:24:52 -07001844 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001845 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001846 final VolumeRecord rec = mRecords.get(fsUuid);
1847 rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001848 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001849 writeSettingsLocked();
1850 }
1851 }
1852
1853 @Override
1854 public void forgetVolume(String fsUuid) {
1855 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1856 waitForReady();
1857
Jeff Sharkey50a05452015-04-29 11:24:52 -07001858 Preconditions.checkNotNull(fsUuid);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001859
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001860 synchronized (mLock) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001861 final VolumeRecord rec = mRecords.remove(fsUuid);
1862 if (rec != null && !TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001863 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001864 }
1865 mCallbacks.notifyVolumeForgotten(fsUuid);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001866
1867 // If this had been primary storage, revert back to internal and
1868 // reset vold so we bind into new volume into place.
1869 if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001870 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001871 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001872 }
1873
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001874 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001875 }
1876 }
1877
Jeff Sharkey7d2af542015-05-12 15:27:15 -07001878 @Override
1879 public void forgetAllVolumes() {
1880 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1881 waitForReady();
1882
Jeff Sharkey50a05452015-04-29 11:24:52 -07001883 synchronized (mLock) {
1884 for (int i = 0; i < mRecords.size(); i++) {
1885 final String fsUuid = mRecords.keyAt(i);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001886 final VolumeRecord rec = mRecords.valueAt(i);
1887 if (!TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001888 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001889 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001890 mCallbacks.notifyVolumeForgotten(fsUuid);
1891 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001892 mRecords.clear();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001893
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001894 if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)) {
1895 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
1896 }
1897
1898 writeSettingsLocked();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001899 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001900 }
1901 }
1902
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001903 private void forgetPartition(String partGuid) {
1904 try {
1905 mConnector.execute("volume", "forget_partition", partGuid);
1906 } catch (NativeDaemonConnectorException e) {
1907 Slog.w(TAG, "Failed to forget key for " + partGuid + ": " + e);
1908 }
1909 }
1910
Svet Ganov6ee871e2015-07-10 14:29:33 -07001911 private void remountUidExternalStorage(int uid, int mode) {
Jeff Sharkey9527b222015-06-24 15:24:48 -07001912 waitForReady();
1913
Svet Ganov6ee871e2015-07-10 14:29:33 -07001914 String modeName = "none";
1915 switch (mode) {
1916 case Zygote.MOUNT_EXTERNAL_DEFAULT: {
1917 modeName = "default";
1918 } break;
1919
1920 case Zygote.MOUNT_EXTERNAL_READ: {
1921 modeName = "read";
1922 } break;
1923
1924 case Zygote.MOUNT_EXTERNAL_WRITE: {
1925 modeName = "write";
1926 } break;
Jeff Sharkey9527b222015-06-24 15:24:48 -07001927 }
1928
1929 try {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001930 mConnector.execute("volume", "remount_uid", uid, modeName);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001931 } catch (NativeDaemonConnectorException e) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001932 Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001933 }
1934 }
1935
1936 @Override
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001937 public void setDebugFlags(int flags, int mask) {
1938 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1939 waitForReady();
1940
Jeff Sharkeyba512352015-11-12 20:17:45 -08001941 if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001942 if (StorageManager.isNativeFileBasedEncryptionEnabled()) {
1943 throw new IllegalStateException(
1944 "Emulation not available on device with native FBE");
1945 }
1946
Jeff Sharkeyba512352015-11-12 20:17:45 -08001947 final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
1948 SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001949
1950 // Perform hard reboot to kick policy into place
1951 mContext.getSystemService(PowerManager.class).reboot(null);
Jeff Sharkeyba512352015-11-12 20:17:45 -08001952 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001953
Jeff Sharkeyba512352015-11-12 20:17:45 -08001954 if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
1955 synchronized (mLock) {
1956 mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
1957
1958 writeSettingsLocked();
1959 mHandler.obtainMessage(H_RESET).sendToTarget();
1960 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001961 }
1962 }
1963
1964 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001965 public String getPrimaryStorageUuid() {
1966 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1967 waitForReady();
1968
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001969 synchronized (mLock) {
1970 return mPrimaryStorageUuid;
1971 }
1972 }
1973
1974 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001975 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
1976 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1977 waitForReady();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001978
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001979 synchronized (mLock) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001980 if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) {
1981 throw new IllegalArgumentException("Primary storage already at " + volumeUuid);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001982 }
1983
1984 if (mMoveCallback != null) {
1985 throw new IllegalStateException("Move already in progress");
1986 }
1987 mMoveCallback = callback;
1988 mMoveTargetUuid = volumeUuid;
1989
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001990 // When moving to/from primary physical volume, we probably just nuked
1991 // the current storage location, so we have nothing to move.
1992 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1993 || Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
1994 Slog.d(TAG, "Skipping move to/from primary physical");
1995 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
1996 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001997 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001998
1999 } else {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07002000 final VolumeInfo from = findStorageForUuid(mPrimaryStorageUuid);
2001 final VolumeInfo to = findStorageForUuid(volumeUuid);
2002
2003 if (from == null) {
2004 Slog.w(TAG, "Failing move due to missing from volume " + mPrimaryStorageUuid);
2005 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2006 return;
2007 } else if (to == null) {
2008 Slog.w(TAG, "Failing move due to missing to volume " + volumeUuid);
2009 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2010 return;
2011 }
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002012
2013 try {
2014 mConnector.execute("volume", "move_storage", from.id, to.id);
2015 } catch (NativeDaemonConnectorException e) {
2016 throw e.rethrowAsParcelableException();
2017 }
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002018 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002019 }
2020 }
2021
2022 @Override
Mike Lockwoodecedfdc2011-06-08 15:11:59 -07002023 public int[] getStorageUsers(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002024 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehatc1b4ce92010-02-16 17:13:03 -08002025 waitForReady();
2026 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002027 final String[] r = NativeDaemonEvent.filterMessageList(
2028 mConnector.executeForList("storage", "users", path),
2029 VoldResponseCode.StorageUsersListResult);
2030
San Mehatc1b4ce92010-02-16 17:13:03 -08002031 // FMT: <pid> <process name>
2032 int[] data = new int[r.length];
2033 for (int i = 0; i < r.length; i++) {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002034 String[] tok = r[i].split(" ");
San Mehatc1b4ce92010-02-16 17:13:03 -08002035 try {
2036 data[i] = Integer.parseInt(tok[0]);
2037 } catch (NumberFormatException nfe) {
San Mehata5078592010-03-25 09:36:54 -07002038 Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
San Mehatc1b4ce92010-02-16 17:13:03 -08002039 return new int[0];
2040 }
2041 }
2042 return data;
2043 } catch (NativeDaemonConnectorException e) {
San Mehata5078592010-03-25 09:36:54 -07002044 Slog.e(TAG, "Failed to retrieve storage users list", e);
San Mehatc1b4ce92010-02-16 17:13:03 -08002045 return new int[0];
2046 }
2047 }
2048
San Mehatb1043402010-02-05 08:26:50 -08002049 private void warnOnNotMounted() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002050 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002051 for (int i = 0; i < mVolumes.size(); i++) {
2052 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07002053 if (vol.isPrimary() && vol.isMountedWritable()) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002054 // Cool beans, we have a mounted primary volume
2055 return;
2056 }
Jeff Sharkey32ee8312012-09-30 13:21:31 -07002057 }
San Mehatb1043402010-02-05 08:26:50 -08002058 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002059
2060 Slog.w(TAG, "No primary storage mounted!");
San Mehatb1043402010-02-05 08:26:50 -08002061 }
2062
San Mehat4270e1e2010-01-29 05:32:19 -08002063 public String[] getSecureContainerList() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002064 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002065 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002066 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002067
San Mehat4270e1e2010-01-29 05:32:19 -08002068 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002069 return NativeDaemonEvent.filterMessageList(
2070 mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
San Mehat4270e1e2010-01-29 05:32:19 -08002071 } catch (NativeDaemonConnectorException e) {
2072 return new String[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002073 }
2074 }
San Mehat36972292010-01-06 11:06:32 -08002075
Kenny Root6dceb882012-04-12 14:23:49 -07002076 public int createSecureContainer(String id, int sizeMb, String fstype, String key,
2077 int ownerUid, boolean external) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002078 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehat207e5382010-02-04 20:46:54 -08002079 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002080 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002081
San Mehatb1043402010-02-05 08:26:50 -08002082 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002083 try {
Jeff Sharkey56cd6462013-06-07 15:09:15 -07002084 mConnector.execute("asec", "create", id, sizeMb, fstype, new SensitiveArg(key),
2085 ownerUid, external ? "1" : "0");
San Mehat4270e1e2010-01-29 05:32:19 -08002086 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002087 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002088 }
San Mehata181b212010-02-11 06:50:20 -08002089
2090 if (rc == StorageResultCode.OperationSucceeded) {
2091 synchronized (mAsecMountSet) {
2092 mAsecMountSet.add(id);
2093 }
2094 }
San Mehat4270e1e2010-01-29 05:32:19 -08002095 return rc;
San Mehat36972292010-01-06 11:06:32 -08002096 }
2097
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002098 @Override
2099 public int resizeSecureContainer(String id, int sizeMb, String key) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002100 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002101 waitForReady();
2102 warnOnNotMounted();
2103
2104 int rc = StorageResultCode.OperationSucceeded;
2105 try {
2106 mConnector.execute("asec", "resize", id, sizeMb, new SensitiveArg(key));
2107 } catch (NativeDaemonConnectorException e) {
2108 rc = StorageResultCode.OperationFailedInternalError;
2109 }
2110 return rc;
2111 }
2112
San Mehat4270e1e2010-01-29 05:32:19 -08002113 public int finalizeSecureContainer(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002114 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehatb1043402010-02-05 08:26:50 -08002115 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002116
San Mehatb1043402010-02-05 08:26:50 -08002117 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002118 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002119 mConnector.execute("asec", "finalize", id);
San Mehata181b212010-02-11 06:50:20 -08002120 /*
2121 * Finalization does a remount, so no need
2122 * to update mAsecMountSet
2123 */
San Mehat4270e1e2010-01-29 05:32:19 -08002124 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002125 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002126 }
San Mehat4270e1e2010-01-29 05:32:19 -08002127 return rc;
San Mehat36972292010-01-06 11:06:32 -08002128 }
2129
Kenny Root6dceb882012-04-12 14:23:49 -07002130 public int fixPermissionsSecureContainer(String id, int gid, String filename) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002131 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Kenny Root6dceb882012-04-12 14:23:49 -07002132 warnOnNotMounted();
2133
2134 int rc = StorageResultCode.OperationSucceeded;
2135 try {
2136 mConnector.execute("asec", "fixperms", id, gid, filename);
2137 /*
2138 * Fix permissions does a remount, so no need to update
2139 * mAsecMountSet
2140 */
2141 } catch (NativeDaemonConnectorException e) {
2142 rc = StorageResultCode.OperationFailedInternalError;
2143 }
2144 return rc;
2145 }
2146
San Mehatd9709982010-02-18 11:43:03 -08002147 public int destroySecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002148 enforcePermission(android.Manifest.permission.ASEC_DESTROY);
San Mehat207e5382010-02-04 20:46:54 -08002149 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002150 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002151
Kenny Rootaa485402010-09-14 14:49:41 -07002152 /*
2153 * Force a GC to make sure AssetManagers in other threads of the
2154 * system_server are cleaned up. We have to do this since AssetManager
2155 * instances are kept as a WeakReference and it's possible we have files
2156 * open on the external storage.
2157 */
2158 Runtime.getRuntime().gc();
2159
San Mehatb1043402010-02-05 08:26:50 -08002160 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002161 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002162 final Command cmd = new Command("asec", "destroy", id);
2163 if (force) {
2164 cmd.appendArg("force");
2165 }
2166 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002167 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002168 int code = e.getCode();
2169 if (code == VoldResponseCode.OpFailedStorageBusy) {
2170 rc = StorageResultCode.OperationFailedStorageBusy;
2171 } else {
2172 rc = StorageResultCode.OperationFailedInternalError;
2173 }
San Mehat02735bc2010-01-26 15:18:08 -08002174 }
San Mehata181b212010-02-11 06:50:20 -08002175
2176 if (rc == StorageResultCode.OperationSucceeded) {
2177 synchronized (mAsecMountSet) {
2178 if (mAsecMountSet.contains(id)) {
2179 mAsecMountSet.remove(id);
2180 }
2181 }
2182 }
2183
San Mehat4270e1e2010-01-29 05:32:19 -08002184 return rc;
San Mehat36972292010-01-06 11:06:32 -08002185 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002186
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002187 public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002188 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002189 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002190 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002191
San Mehata181b212010-02-11 06:50:20 -08002192 synchronized (mAsecMountSet) {
2193 if (mAsecMountSet.contains(id)) {
2194 return StorageResultCode.OperationFailedStorageMounted;
2195 }
2196 }
2197
San Mehatb1043402010-02-05 08:26:50 -08002198 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002199 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002200 mConnector.execute("asec", "mount", id, new SensitiveArg(key), ownerUid,
2201 readOnly ? "ro" : "rw");
San Mehat4270e1e2010-01-29 05:32:19 -08002202 } catch (NativeDaemonConnectorException e) {
Kenny Rootf0304622010-03-19 19:20:42 -07002203 int code = e.getCode();
2204 if (code != VoldResponseCode.OpFailedStorageBusy) {
2205 rc = StorageResultCode.OperationFailedInternalError;
2206 }
San Mehat02735bc2010-01-26 15:18:08 -08002207 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002208
2209 if (rc == StorageResultCode.OperationSucceeded) {
2210 synchronized (mAsecMountSet) {
2211 mAsecMountSet.add(id);
2212 }
2213 }
San Mehat4270e1e2010-01-29 05:32:19 -08002214 return rc;
San Mehat36972292010-01-06 11:06:32 -08002215 }
2216
San Mehatd9709982010-02-18 11:43:03 -08002217 public int unmountSecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002218 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002219 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002220 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002221
San Mehat6cdd9c02010-02-09 14:45:20 -08002222 synchronized (mAsecMountSet) {
2223 if (!mAsecMountSet.contains(id)) {
San Mehata181b212010-02-11 06:50:20 -08002224 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehat6cdd9c02010-02-09 14:45:20 -08002225 }
2226 }
2227
Kenny Rootaa485402010-09-14 14:49:41 -07002228 /*
2229 * Force a GC to make sure AssetManagers in other threads of the
2230 * system_server are cleaned up. We have to do this since AssetManager
2231 * instances are kept as a WeakReference and it's possible we have files
2232 * open on the external storage.
2233 */
2234 Runtime.getRuntime().gc();
2235
San Mehatb1043402010-02-05 08:26:50 -08002236 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002237 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002238 final Command cmd = new Command("asec", "unmount", id);
2239 if (force) {
2240 cmd.appendArg("force");
2241 }
2242 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002243 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002244 int code = e.getCode();
2245 if (code == VoldResponseCode.OpFailedStorageBusy) {
2246 rc = StorageResultCode.OperationFailedStorageBusy;
2247 } else {
2248 rc = StorageResultCode.OperationFailedInternalError;
2249 }
San Mehat02735bc2010-01-26 15:18:08 -08002250 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002251
2252 if (rc == StorageResultCode.OperationSucceeded) {
2253 synchronized (mAsecMountSet) {
2254 mAsecMountSet.remove(id);
2255 }
2256 }
San Mehat4270e1e2010-01-29 05:32:19 -08002257 return rc;
San Mehat9dba7092010-01-18 06:47:41 -08002258 }
2259
San Mehat6cdd9c02010-02-09 14:45:20 -08002260 public boolean isSecureContainerMounted(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002261 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat6cdd9c02010-02-09 14:45:20 -08002262 waitForReady();
2263 warnOnNotMounted();
2264
2265 synchronized (mAsecMountSet) {
2266 return mAsecMountSet.contains(id);
2267 }
2268 }
2269
San Mehat4270e1e2010-01-29 05:32:19 -08002270 public int renameSecureContainer(String oldId, String newId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002271 enforcePermission(android.Manifest.permission.ASEC_RENAME);
San Mehat207e5382010-02-04 20:46:54 -08002272 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002273 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002274
San Mehata181b212010-02-11 06:50:20 -08002275 synchronized (mAsecMountSet) {
San Mehat85451ee2010-02-24 08:54:18 -08002276 /*
Jason parks9ed98bc2011-01-17 09:58:35 -06002277 * Because a mounted container has active internal state which cannot be
San Mehat85451ee2010-02-24 08:54:18 -08002278 * changed while active, we must ensure both ids are not currently mounted.
2279 */
2280 if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
San Mehata181b212010-02-11 06:50:20 -08002281 return StorageResultCode.OperationFailedStorageMounted;
2282 }
2283 }
2284
San Mehatb1043402010-02-05 08:26:50 -08002285 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002286 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002287 mConnector.execute("asec", "rename", oldId, newId);
San Mehat4270e1e2010-01-29 05:32:19 -08002288 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002289 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002290 }
San Mehata181b212010-02-11 06:50:20 -08002291
San Mehat4270e1e2010-01-29 05:32:19 -08002292 return rc;
San Mehat45f61042010-01-23 08:12:43 -08002293 }
2294
San Mehat4270e1e2010-01-29 05:32:19 -08002295 public String getSecureContainerPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002296 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002297 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002298 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002299
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002300 final NativeDaemonEvent event;
San Mehat2d66cef2010-03-23 11:12:52 -07002301 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002302 event = mConnector.execute("asec", "path", id);
2303 event.checkCode(VoldResponseCode.AsecPathResult);
2304 return event.getMessage();
San Mehat2d66cef2010-03-23 11:12:52 -07002305 } catch (NativeDaemonConnectorException e) {
2306 int code = e.getCode();
2307 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Fredrik Helmera20c8ef2011-02-09 16:16:10 +01002308 Slog.i(TAG, String.format("Container '%s' not found", id));
2309 return null;
San Mehat22dd86e2010-01-12 12:21:18 -08002310 } else {
San Mehat2d66cef2010-03-23 11:12:52 -07002311 throw new IllegalStateException(String.format("Unexpected response code %d", code));
San Mehat22dd86e2010-01-12 12:21:18 -08002312 }
2313 }
San Mehat22dd86e2010-01-12 12:21:18 -08002314 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002315
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002316 public String getSecureContainerFilesystemPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002317 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002318 waitForReady();
2319 warnOnNotMounted();
2320
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002321 final NativeDaemonEvent event;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002322 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002323 event = mConnector.execute("asec", "fspath", id);
2324 event.checkCode(VoldResponseCode.AsecPathResult);
2325 return event.getMessage();
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002326 } catch (NativeDaemonConnectorException e) {
2327 int code = e.getCode();
2328 if (code == VoldResponseCode.OpFailedStorageNotFound) {
2329 Slog.i(TAG, String.format("Container '%s' not found", id));
2330 return null;
2331 } else {
2332 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2333 }
2334 }
2335 }
2336
Jeff Sharkey48877892015-03-18 11:27:19 -07002337 @Override
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002338 public void finishMediaUpdate() {
Jeff Sharkey9527b222015-06-24 15:24:48 -07002339 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
Rubin Xucd7a0142015-04-17 23:45:27 +01002340 throw new SecurityException("no permission to call finishMediaUpdate()");
2341 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002342 if (mUnmountSignal != null) {
2343 mUnmountSignal.countDown();
2344 } else {
2345 Slog.w(TAG, "Odd, nobody asked to unmount?");
2346 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002347 }
Kenny Root02c87302010-07-01 08:10:18 -07002348
Kenny Roota02b8b02010-08-05 16:14:17 -07002349 private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
2350 if (callerUid == android.os.Process.SYSTEM_UID) {
2351 return true;
2352 }
2353
Kenny Root02c87302010-07-01 08:10:18 -07002354 if (packageName == null) {
2355 return false;
2356 }
2357
Jeff Sharkeycd654482016-01-08 17:42:11 -07002358 final int packageUid = mPms.getPackageUid(packageName,
2359 PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callerUid));
Kenny Root02c87302010-07-01 08:10:18 -07002360
2361 if (DEBUG_OBB) {
2362 Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
2363 packageUid + ", callerUid = " + callerUid);
2364 }
2365
2366 return callerUid == packageUid;
2367 }
2368
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002369 public String getMountedObbPath(String rawPath) {
2370 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002371
Kenny Root02c87302010-07-01 08:10:18 -07002372 waitForReady();
2373 warnOnNotMounted();
2374
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002375 final ObbState state;
Rubin Xucd7a0142015-04-17 23:45:27 +01002376 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002377 state = mObbPathToStateMap.get(rawPath);
2378 }
2379 if (state == null) {
2380 Slog.w(TAG, "Failed to find OBB mounted at " + rawPath);
2381 return null;
2382 }
2383
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002384 final NativeDaemonEvent event;
Kenny Root02c87302010-07-01 08:10:18 -07002385 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07002386 event = mConnector.execute("obb", "path", state.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002387 event.checkCode(VoldResponseCode.AsecPathResult);
2388 return event.getMessage();
Kenny Root02c87302010-07-01 08:10:18 -07002389 } catch (NativeDaemonConnectorException e) {
2390 int code = e.getCode();
2391 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Kenny Roota02b8b02010-08-05 16:14:17 -07002392 return null;
Kenny Root02c87302010-07-01 08:10:18 -07002393 } else {
2394 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2395 }
2396 }
2397 }
2398
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002399 @Override
2400 public boolean isObbMounted(String rawPath) {
2401 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002402 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002403 return mObbPathToStateMap.containsKey(rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002404 }
Kenny Root02c87302010-07-01 08:10:18 -07002405 }
2406
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002407 @Override
2408 public void mountObb(
2409 String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) {
2410 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2411 Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
2412 Preconditions.checkNotNull(token, "token cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002413
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002414 final int callingUid = Binder.getCallingUid();
2415 final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce);
2416 final ObbAction action = new MountObbAction(obbState, key, callingUid);
Kenny Roota02b8b02010-08-05 16:14:17 -07002417 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
2418
2419 if (DEBUG_OBB)
2420 Slog.i(TAG, "Send to OBB handler: " + action.toString());
Kenny Root02c87302010-07-01 08:10:18 -07002421 }
2422
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002423 @Override
2424 public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
2425 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2426
2427 final ObbState existingState;
Rubin Xucd7a0142015-04-17 23:45:27 +01002428 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002429 existingState = mObbPathToStateMap.get(rawPath);
Kenny Rootf1121dc2010-09-29 07:30:53 -07002430 }
2431
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002432 if (existingState != null) {
2433 // TODO: separate state object from request data
2434 final int callingUid = Binder.getCallingUid();
2435 final ObbState newState = new ObbState(
2436 rawPath, existingState.canonicalPath, callingUid, token, nonce);
2437 final ObbAction action = new UnmountObbAction(newState, force);
2438 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root02c87302010-07-01 08:10:18 -07002439
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002440 if (DEBUG_OBB)
2441 Slog.i(TAG, "Send to OBB handler: " + action.toString());
2442 } else {
2443 Slog.w(TAG, "Unknown OBB mount at " + rawPath);
2444 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002445 }
2446
Ben Komalo444eca22011-09-01 15:17:44 -07002447 @Override
2448 public int getEncryptionState() {
2449 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2450 "no permission to access the crypt keeper");
2451
2452 waitForReady();
2453
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002454 final NativeDaemonEvent event;
Ben Komalo444eca22011-09-01 15:17:44 -07002455 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002456 event = mCryptConnector.execute("cryptfs", "cryptocomplete");
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002457 return Integer.parseInt(event.getMessage());
Ben Komalo444eca22011-09-01 15:17:44 -07002458 } catch (NumberFormatException e) {
2459 // Bad result - unexpected.
2460 Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
2461 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2462 } catch (NativeDaemonConnectorException e) {
2463 // Something bad happened.
2464 Slog.w(TAG, "Error in communicating with cryptfs in validating");
2465 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2466 }
2467 }
2468
2469 @Override
Jason parks5af0b912010-11-29 09:05:25 -06002470 public int decryptStorage(String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002471 if (TextUtils.isEmpty(password)) {
2472 throw new IllegalArgumentException("password cannot be empty");
Jason parks5af0b912010-11-29 09:05:25 -06002473 }
2474
Jason parks8888c592011-01-20 22:46:41 -06002475 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2476 "no permission to access the crypt keeper");
Jason parks5af0b912010-11-29 09:05:25 -06002477
2478 waitForReady();
2479
2480 if (DEBUG_EVENTS) {
2481 Slog.i(TAG, "decrypting storage...");
2482 }
2483
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002484 final NativeDaemonEvent event;
Jason parks5af0b912010-11-29 09:05:25 -06002485 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002486 event = mCryptConnector.execute("cryptfs", "checkpw", new SensitiveArg(password));
Jason parks9ed98bc2011-01-17 09:58:35 -06002487
Fredrik Roubertda6aedf2011-12-20 17:34:43 +01002488 final int code = Integer.parseInt(event.getMessage());
Jason parks9ed98bc2011-01-17 09:58:35 -06002489 if (code == 0) {
2490 // Decrypt was successful. Post a delayed message before restarting in order
2491 // to let the UI to clear itself
2492 mHandler.postDelayed(new Runnable() {
2493 public void run() {
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002494 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002495 mCryptConnector.execute("cryptfs", "restart");
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002496 } catch (NativeDaemonConnectorException e) {
2497 Slog.e(TAG, "problem executing in background", e);
2498 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002499 }
Jason parksf7b3cd42011-01-27 09:28:25 -06002500 }, 1000); // 1 second
Jason parks9ed98bc2011-01-17 09:58:35 -06002501 }
2502
2503 return code;
Jason parks5af0b912010-11-29 09:05:25 -06002504 } catch (NativeDaemonConnectorException e) {
2505 // Decryption failed
2506 return e.getCode();
2507 }
Jason parks5af0b912010-11-29 09:05:25 -06002508 }
2509
Paul Lawrence46791e72014-04-03 09:10:26 -07002510 public int encryptStorage(int type, String password) {
2511 if (TextUtils.isEmpty(password) && type != StorageManager.CRYPT_TYPE_DEFAULT) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002512 throw new IllegalArgumentException("password cannot be empty");
Jason parks56aa5322011-01-07 09:01:15 -06002513 }
2514
Jason parks8888c592011-01-20 22:46:41 -06002515 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2516 "no permission to access the crypt keeper");
Jason parks56aa5322011-01-07 09:01:15 -06002517
2518 waitForReady();
2519
2520 if (DEBUG_EVENTS) {
Jason parks8888c592011-01-20 22:46:41 -06002521 Slog.i(TAG, "encrypting storage...");
Jason parks56aa5322011-01-07 09:01:15 -06002522 }
2523
2524 try {
Paul Lawrence5096d9e2015-09-09 13:05:45 -07002525 if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
2526 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2527 CRYPTO_TYPES[type]);
2528 } else {
2529 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2530 CRYPTO_TYPES[type], new SensitiveArg(password));
2531 }
Jason parks56aa5322011-01-07 09:01:15 -06002532 } catch (NativeDaemonConnectorException e) {
2533 // Encryption failed
2534 return e.getCode();
2535 }
2536
2537 return 0;
2538 }
2539
Paul Lawrence8e397362014-01-27 15:22:30 -08002540 /** Set the password for encrypting the master key.
2541 * @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
2542 * @param password The password to set.
2543 */
2544 public int changeEncryptionPassword(int type, String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002545 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2546 "no permission to access the crypt keeper");
2547
2548 waitForReady();
2549
2550 if (DEBUG_EVENTS) {
2551 Slog.i(TAG, "changing encryption password...");
2552 }
2553
2554 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002555 NativeDaemonEvent event = mCryptConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type],
Paul Lawrence05487612015-06-09 13:35:38 -07002556 new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002557 return Integer.parseInt(event.getMessage());
Jason parksf7b3cd42011-01-27 09:28:25 -06002558 } catch (NativeDaemonConnectorException e) {
2559 // Encryption failed
2560 return e.getCode();
2561 }
2562 }
2563
Christopher Tate32418be2011-10-10 13:51:12 -07002564 /**
2565 * Validate a user-supplied password string with cryptfs
2566 */
2567 @Override
2568 public int verifyEncryptionPassword(String password) throws RemoteException {
2569 // Only the system process is permitted to validate passwords
2570 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2571 throw new SecurityException("no permission to access the crypt keeper");
2572 }
2573
2574 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2575 "no permission to access the crypt keeper");
2576
2577 if (TextUtils.isEmpty(password)) {
2578 throw new IllegalArgumentException("password cannot be empty");
2579 }
2580
2581 waitForReady();
2582
2583 if (DEBUG_EVENTS) {
2584 Slog.i(TAG, "validating encryption password...");
2585 }
2586
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002587 final NativeDaemonEvent event;
Christopher Tate32418be2011-10-10 13:51:12 -07002588 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002589 event = mCryptConnector.execute("cryptfs", "verifypw", new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002590 Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
2591 return Integer.parseInt(event.getMessage());
Christopher Tate32418be2011-10-10 13:51:12 -07002592 } catch (NativeDaemonConnectorException e) {
2593 // Encryption failed
2594 return e.getCode();
2595 }
2596 }
2597
Paul Lawrence8e397362014-01-27 15:22:30 -08002598 /**
2599 * Get the type of encryption used to encrypt the master key.
2600 * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
2601 */
2602 @Override
Svetoslav16e4a1a2014-09-29 18:16:20 -07002603 public int getPasswordType() {
Paul Lawrence8e397362014-01-27 15:22:30 -08002604
2605 waitForReady();
2606
2607 final NativeDaemonEvent event;
2608 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002609 event = mCryptConnector.execute("cryptfs", "getpwtype");
Paul Lawrence8e397362014-01-27 15:22:30 -08002610 for (int i = 0; i < CRYPTO_TYPES.length; ++i) {
2611 if (CRYPTO_TYPES[i].equals(event.getMessage()))
2612 return i;
2613 }
2614
2615 throw new IllegalStateException("unexpected return from cryptfs");
2616 } catch (NativeDaemonConnectorException e) {
2617 throw e.rethrowAsParcelableException();
2618 }
2619 }
2620
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002621 /**
2622 * Set a field in the crypto header.
2623 * @param field field to set
2624 * @param contents contents to set in field
2625 */
2626 @Override
2627 public void setField(String field, String contents) throws RemoteException {
2628
2629 waitForReady();
2630
2631 final NativeDaemonEvent event;
2632 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002633 event = mCryptConnector.execute("cryptfs", "setfield", field, contents);
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002634 } catch (NativeDaemonConnectorException e) {
2635 throw e.rethrowAsParcelableException();
2636 }
2637 }
2638
2639 /**
2640 * Gets a field from the crypto header.
2641 * @param field field to get
2642 * @return contents of field
2643 */
2644 @Override
2645 public String getField(String field) throws RemoteException {
2646
2647 waitForReady();
2648
2649 final NativeDaemonEvent event;
2650 try {
2651 final String[] contents = NativeDaemonEvent.filterMessageList(
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002652 mCryptConnector.executeForList("cryptfs", "getfield", field),
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002653 VoldResponseCode.CryptfsGetfieldResult);
2654 String result = new String();
2655 for (String content : contents) {
2656 result += content;
2657 }
2658 return result;
2659 } catch (NativeDaemonConnectorException e) {
2660 throw e.rethrowAsParcelableException();
2661 }
2662 }
2663
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002664 /**
2665 * Is userdata convertible to file based encryption?
2666 * @return non zero for convertible
2667 */
2668 @Override
2669 public boolean isConvertibleToFBE() throws RemoteException {
2670
2671 waitForReady();
2672
2673 final NativeDaemonEvent event;
2674 try {
2675 event = mCryptConnector.execute("cryptfs", "isConvertibleToFBE");
2676 return Integer.parseInt(event.getMessage()) != 0;
2677 } catch (NativeDaemonConnectorException e) {
2678 throw e.rethrowAsParcelableException();
2679 }
2680 }
2681
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002682 @Override
Paul Lawrence945490c2014-03-27 16:37:28 +00002683 public String getPassword() throws RemoteException {
Rubin Xucd7a0142015-04-17 23:45:27 +01002684 mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE,
2685 "only keyguard can retrieve password");
Paul Lawrence945490c2014-03-27 16:37:28 +00002686 if (!isReady()) {
2687 return new String();
2688 }
2689
2690 final NativeDaemonEvent event;
2691 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002692 event = mCryptConnector.execute("cryptfs", "getpw");
Paul Lawrence24063b52015-01-06 13:11:23 -08002693 if ("-1".equals(event.getMessage())) {
2694 // -1 equals no password
2695 return null;
2696 }
Paul Lawrence05487612015-06-09 13:35:38 -07002697 return event.getMessage();
Paul Lawrence945490c2014-03-27 16:37:28 +00002698 } catch (NativeDaemonConnectorException e) {
2699 throw e.rethrowAsParcelableException();
Paul Lawrence24063b52015-01-06 13:11:23 -08002700 } catch (IllegalArgumentException e) {
2701 Slog.e(TAG, "Invalid response to getPassword");
2702 return null;
Paul Lawrence945490c2014-03-27 16:37:28 +00002703 }
2704 }
2705
2706 @Override
2707 public void clearPassword() throws RemoteException {
2708 if (!isReady()) {
2709 return;
2710 }
2711
2712 final NativeDaemonEvent event;
2713 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002714 event = mCryptConnector.execute("cryptfs", "clearpw");
Paul Lawrence945490c2014-03-27 16:37:28 +00002715 } catch (NativeDaemonConnectorException e) {
2716 throw e.rethrowAsParcelableException();
2717 }
2718 }
2719
2720 @Override
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002721 public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002722 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002723 waitForReady();
2724
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002725 try {
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002726 mCryptConnector.execute("cryptfs", "create_user_key", userId, serialNumber,
2727 ephemeral ? 1 : 0);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002728 } catch (NativeDaemonConnectorException e) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002729 throw e.rethrowAsParcelableException();
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002730 }
2731 }
2732
Paul Crowley7ec733f2015-05-19 12:42:00 +01002733 @Override
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002734 public void destroyUserKey(int userId) {
2735 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowley7ec733f2015-05-19 12:42:00 +01002736 waitForReady();
2737
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002738 try {
2739 mCryptConnector.execute("cryptfs", "destroy_user_key", userId);
2740 } catch (NativeDaemonConnectorException e) {
2741 throw e.rethrowAsParcelableException();
2742 }
2743 }
2744
2745 @Override
2746 public void unlockUserKey(int userId, int serialNumber, byte[] token) {
2747 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2748 waitForReady();
2749
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07002750 // When a user has secure lock screen, require a challenge token to
2751 // actually unlock. This check is mostly in place for emulation mode.
2752 if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(token)) {
2753 throw new IllegalStateException("Token required to unlock secure user " + userId);
2754 }
2755
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002756 final String encodedToken;
2757 if (ArrayUtils.isEmpty(token)) {
2758 encodedToken = "!";
2759 } else {
2760 encodedToken = HexDump.toHexString(token);
Paul Crowley7ec733f2015-05-19 12:42:00 +01002761 }
2762
2763 try {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002764 mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber,
2765 new SensitiveArg(encodedToken));
Paul Crowley7ec733f2015-05-19 12:42:00 +01002766 } catch (NativeDaemonConnectorException e) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002767 throw e.rethrowAsParcelableException();
2768 }
2769
2770 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002771 mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002772 }
2773 }
2774
2775 @Override
2776 public void lockUserKey(int userId) {
2777 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2778 waitForReady();
2779
2780 try {
2781 mCryptConnector.execute("cryptfs", "lock_user_key", userId);
2782 } catch (NativeDaemonConnectorException e) {
2783 throw e.rethrowAsParcelableException();
2784 }
2785
2786 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002787 mLocalUnlockedUsers = ArrayUtils.removeInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002788 }
2789 }
2790
2791 @Override
2792 public boolean isUserKeyUnlocked(int userId) {
Jeff Sharkeyba512352015-11-12 20:17:45 -08002793 if (StorageManager.isFileBasedEncryptionEnabled()) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002794 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002795 return ArrayUtils.contains(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002796 }
2797 } else {
2798 return true;
2799 }
2800 }
2801
2802 @Override
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002803 public void prepareUserStorage(
2804 String volumeUuid, int userId, int serialNumber, boolean ephemeral) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002805 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2806 waitForReady();
2807
2808 try {
2809 mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid),
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002810 userId, serialNumber, ephemeral ? 1 : 0);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002811 } catch (NativeDaemonConnectorException e) {
2812 throw e.rethrowAsParcelableException();
Paul Crowley7ec733f2015-05-19 12:42:00 +01002813 }
2814 }
2815
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002816 @Override
Daichi Hirono91e3b502015-12-16 09:24:16 +09002817 public ParcelFileDescriptor mountAppFuse(final String name) throws RemoteException {
Daichi Hironobee50c02015-12-14 11:00:54 +09002818 try {
Daichi Hirono91e3b502015-12-16 09:24:16 +09002819 final int uid = Binder.getCallingUid();
Daichi Hironofd7d57e2016-01-29 14:30:58 +09002820 final int pid = Binder.getCallingPid();
Daichi Hironobee50c02015-12-14 11:00:54 +09002821 final NativeDaemonEvent event =
Daichi Hironofd7d57e2016-01-29 14:30:58 +09002822 mConnector.execute("appfuse", "mount", uid, pid, name);
Daichi Hironobee50c02015-12-14 11:00:54 +09002823 if (event.getFileDescriptors() == null) {
Daichi Hirono91e3b502015-12-16 09:24:16 +09002824 throw new RemoteException("AppFuse FD from vold is null.");
Daichi Hironobee50c02015-12-14 11:00:54 +09002825 }
Daichi Hirono91e3b502015-12-16 09:24:16 +09002826 return ParcelFileDescriptor.fromFd(
2827 event.getFileDescriptors()[0],
2828 mHandler,
2829 new ParcelFileDescriptor.OnCloseListener() {
2830 @Override
2831 public void onClose(IOException e) {
2832 try {
2833 final NativeDaemonEvent event = mConnector.execute(
Daichi Hironofd7d57e2016-01-29 14:30:58 +09002834 "appfuse", "unmount", uid, pid, name);
Daichi Hirono91e3b502015-12-16 09:24:16 +09002835 } catch (NativeDaemonConnectorException unmountException) {
2836 Log.e(TAG, "Failed to unmount appfuse.");
2837 }
2838 }
2839 });
Daichi Hironobee50c02015-12-14 11:00:54 +09002840 } catch (NativeDaemonConnectorException e) {
2841 throw e.rethrowAsParcelableException();
Daichi Hirono91e3b502015-12-16 09:24:16 +09002842 } catch (IOException e) {
2843 throw new RemoteException(e.getMessage());
Daichi Hironobee50c02015-12-14 11:00:54 +09002844 }
Daichi Hirono9e8d9e22015-11-13 14:37:00 +09002845 }
2846
2847 @Override
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002848 public int mkdirs(String callingPkg, String appPath) {
2849 final int userId = UserHandle.getUserId(Binder.getCallingUid());
2850 final UserEnvironment userEnv = new UserEnvironment(userId);
2851
2852 // Validate that reported package name belongs to caller
2853 final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
2854 Context.APP_OPS_SERVICE);
2855 appOps.checkPackage(Binder.getCallingUid(), callingPkg);
2856
Jeff Sharkey48877892015-03-18 11:27:19 -07002857 File appFile = null;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002858 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07002859 appFile = new File(appPath).getCanonicalFile();
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002860 } catch (IOException e) {
2861 Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
2862 return -1;
2863 }
2864
2865 // Try translating the app path into a vold path, but require that it
2866 // belong to the calling package.
Jeff Sharkey48877892015-03-18 11:27:19 -07002867 if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) ||
2868 FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) ||
2869 FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) {
2870 appPath = appFile.getAbsolutePath();
2871 if (!appPath.endsWith("/")) {
2872 appPath = appPath + "/";
2873 }
2874
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002875 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07002876 mConnector.execute("volume", "mkdirs", appPath);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002877 return 0;
2878 } catch (NativeDaemonConnectorException e) {
2879 return e.getCode();
2880 }
2881 }
2882
Jeff Sharkey48877892015-03-18 11:27:19 -07002883 throw new SecurityException("Invalid mkdirs path: " + appFile);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002884 }
2885
2886 @Override
Jeff Sharkey46349872015-07-28 10:49:47 -07002887 public StorageVolume[] getVolumeList(int uid, String packageName, int flags) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002888 final int userId = UserHandle.getUserId(uid);
Jeff Sharkey46349872015-07-28 10:49:47 -07002889 final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0;
2890
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002891 boolean reportUnmounted = false;
Jeff Sharkey48877892015-03-18 11:27:19 -07002892 boolean foundPrimary = false;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002893
Svetoslav38c3dbb2015-07-14 11:27:06 -07002894 final long identity = Binder.clearCallingIdentity();
2895 try {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002896 if (!mMountServiceInternal.hasExternalStorage(uid, packageName)) {
2897 reportUnmounted = true;
2898 }
2899 if (!isUserKeyUnlocked(userId)) {
2900 reportUnmounted = true;
2901 }
Svetoslav38c3dbb2015-07-14 11:27:06 -07002902 } finally {
2903 Binder.restoreCallingIdentity(identity);
2904 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07002905
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002906 final ArrayList<StorageVolume> res = new ArrayList<>();
Jeff Sharkey48877892015-03-18 11:27:19 -07002907 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002908 for (int i = 0; i < mVolumes.size(); i++) {
2909 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey46349872015-07-28 10:49:47 -07002910 if (forWrite ? vol.isVisibleForWrite(userId) : vol.isVisibleForRead(userId)) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07002911 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
2912 reportUnmounted);
Jeff Sharkey48877892015-03-18 11:27:19 -07002913 if (vol.isPrimary()) {
2914 res.add(0, userVol);
2915 foundPrimary = true;
2916 } else {
2917 res.add(userVol);
2918 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002919 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002920 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002921 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002922
2923 if (!foundPrimary) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002924 Log.w(TAG, "No primary storage defined yet; hacking together a stub");
Jeff Sharkey48877892015-03-18 11:27:19 -07002925
2926 final boolean primaryPhysical = SystemProperties.getBoolean(
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002927 StorageManager.PROP_PRIMARY_PHYSICAL, false);
Jeff Sharkey48877892015-03-18 11:27:19 -07002928
2929 final String id = "stub_primary";
2930 final File path = Environment.getLegacyExternalStorageDirectory();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002931 final String description = mContext.getString(android.R.string.unknownName);
Jeff Sharkey48877892015-03-18 11:27:19 -07002932 final boolean primary = true;
2933 final boolean removable = primaryPhysical;
2934 final boolean emulated = !primaryPhysical;
2935 final long mtpReserveSize = 0L;
2936 final boolean allowMassStorage = false;
2937 final long maxFileSize = 0L;
2938 final UserHandle owner = new UserHandle(userId);
2939 final String uuid = null;
Jeff Sharkey48877892015-03-18 11:27:19 -07002940 final String state = Environment.MEDIA_REMOVED;
2941
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07002942 res.add(0, new StorageVolume(id, StorageVolume.STORAGE_ID_INVALID, path,
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002943 description, primary, removable, emulated, mtpReserveSize,
2944 allowMassStorage, maxFileSize, owner, uuid, state));
Jeff Sharkey48877892015-03-18 11:27:19 -07002945 }
2946
2947 return res.toArray(new StorageVolume[res.size()]);
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002948 }
2949
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002950 @Override
2951 public DiskInfo[] getDisks() {
2952 synchronized (mLock) {
2953 final DiskInfo[] res = new DiskInfo[mDisks.size()];
2954 for (int i = 0; i < mDisks.size(); i++) {
2955 res[i] = mDisks.valueAt(i);
2956 }
2957 return res;
2958 }
2959 }
2960
2961 @Override
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07002962 public VolumeInfo[] getVolumes(int flags) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002963 synchronized (mLock) {
2964 final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
2965 for (int i = 0; i < mVolumes.size(); i++) {
2966 res[i] = mVolumes.valueAt(i);
2967 }
2968 return res;
2969 }
2970 }
2971
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07002972 @Override
2973 public VolumeRecord[] getVolumeRecords(int flags) {
2974 synchronized (mLock) {
2975 final VolumeRecord[] res = new VolumeRecord[mRecords.size()];
2976 for (int i = 0; i < mRecords.size(); i++) {
2977 res[i] = mRecords.valueAt(i);
2978 }
2979 return res;
2980 }
2981 }
2982
Kenny Rootaf9d6672010-10-08 09:21:39 -07002983 private void addObbStateLocked(ObbState obbState) throws RemoteException {
2984 final IBinder binder = obbState.getBinder();
2985 List<ObbState> obbStates = mObbMounts.get(binder);
Kenny Root5919ac62010-10-05 09:49:40 -07002986
Kenny Rootaf9d6672010-10-08 09:21:39 -07002987 if (obbStates == null) {
2988 obbStates = new ArrayList<ObbState>();
2989 mObbMounts.put(binder, obbStates);
2990 } else {
2991 for (final ObbState o : obbStates) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002992 if (o.rawPath.equals(obbState.rawPath)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07002993 throw new IllegalStateException("Attempt to add ObbState twice. "
2994 + "This indicates an error in the MountService logic.");
Kenny Root5919ac62010-10-05 09:49:40 -07002995 }
2996 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002997 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07002998
2999 obbStates.add(obbState);
3000 try {
3001 obbState.link();
3002 } catch (RemoteException e) {
3003 /*
3004 * The binder died before we could link it, so clean up our state
3005 * and return failure.
3006 */
3007 obbStates.remove(obbState);
3008 if (obbStates.isEmpty()) {
3009 mObbMounts.remove(binder);
3010 }
3011
3012 // Rethrow the error so mountObb can get it
3013 throw e;
3014 }
3015
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003016 mObbPathToStateMap.put(obbState.rawPath, obbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003017 }
3018
Kenny Rootaf9d6672010-10-08 09:21:39 -07003019 private void removeObbStateLocked(ObbState obbState) {
3020 final IBinder binder = obbState.getBinder();
3021 final List<ObbState> obbStates = mObbMounts.get(binder);
3022 if (obbStates != null) {
3023 if (obbStates.remove(obbState)) {
3024 obbState.unlink();
Kenny Root05105f72010-09-22 17:29:43 -07003025 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003026 if (obbStates.isEmpty()) {
3027 mObbMounts.remove(binder);
3028 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003029 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003030
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003031 mObbPathToStateMap.remove(obbState.rawPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003032 }
3033
Kenny Roota02b8b02010-08-05 16:14:17 -07003034 private class ObbActionHandler extends Handler {
3035 private boolean mBound = false;
Kenny Root480afe72010-10-07 10:17:50 -07003036 private final List<ObbAction> mActions = new LinkedList<ObbAction>();
Kenny Roota02b8b02010-08-05 16:14:17 -07003037
3038 ObbActionHandler(Looper l) {
3039 super(l);
3040 }
3041
3042 @Override
3043 public void handleMessage(Message msg) {
3044 switch (msg.what) {
3045 case OBB_RUN_ACTION: {
Kenny Root480afe72010-10-07 10:17:50 -07003046 final ObbAction action = (ObbAction) msg.obj;
Kenny Roota02b8b02010-08-05 16:14:17 -07003047
3048 if (DEBUG_OBB)
3049 Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
3050
3051 // If a bind was already initiated we don't really
3052 // need to do anything. The pending install
3053 // will be processed later on.
3054 if (!mBound) {
3055 // If this is the only one pending we might
3056 // have to bind to the service again.
3057 if (!connectToService()) {
3058 Slog.e(TAG, "Failed to bind to media container service");
3059 action.handleError();
3060 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003061 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003062 }
Kenny Root735de3b2010-09-30 14:11:39 -07003063
Kenny Root735de3b2010-09-30 14:11:39 -07003064 mActions.add(action);
Kenny Roota02b8b02010-08-05 16:14:17 -07003065 break;
3066 }
3067 case OBB_MCS_BOUND: {
3068 if (DEBUG_OBB)
3069 Slog.i(TAG, "OBB_MCS_BOUND");
3070 if (msg.obj != null) {
3071 mContainerService = (IMediaContainerService) msg.obj;
3072 }
3073 if (mContainerService == null) {
3074 // Something seriously wrong. Bail out
3075 Slog.e(TAG, "Cannot bind to media container service");
3076 for (ObbAction action : mActions) {
3077 // Indicate service bind error
3078 action.handleError();
3079 }
3080 mActions.clear();
3081 } else if (mActions.size() > 0) {
Kenny Root480afe72010-10-07 10:17:50 -07003082 final ObbAction action = mActions.get(0);
Kenny Roota02b8b02010-08-05 16:14:17 -07003083 if (action != null) {
3084 action.execute(this);
3085 }
3086 } else {
3087 // Should never happen ideally.
3088 Slog.w(TAG, "Empty queue");
3089 }
3090 break;
3091 }
3092 case OBB_MCS_RECONNECT: {
3093 if (DEBUG_OBB)
3094 Slog.i(TAG, "OBB_MCS_RECONNECT");
3095 if (mActions.size() > 0) {
3096 if (mBound) {
3097 disconnectService();
3098 }
3099 if (!connectToService()) {
3100 Slog.e(TAG, "Failed to bind to media container service");
3101 for (ObbAction action : mActions) {
3102 // Indicate service bind error
3103 action.handleError();
3104 }
3105 mActions.clear();
3106 }
3107 }
3108 break;
3109 }
3110 case OBB_MCS_UNBIND: {
3111 if (DEBUG_OBB)
3112 Slog.i(TAG, "OBB_MCS_UNBIND");
3113
3114 // Delete pending install
3115 if (mActions.size() > 0) {
3116 mActions.remove(0);
3117 }
3118 if (mActions.size() == 0) {
3119 if (mBound) {
3120 disconnectService();
3121 }
3122 } else {
3123 // There are more pending requests in queue.
3124 // Just post MCS_BOUND message to trigger processing
3125 // of next pending install.
3126 mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
3127 }
3128 break;
3129 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003130 case OBB_FLUSH_MOUNT_STATE: {
3131 final String path = (String) msg.obj;
3132
3133 if (DEBUG_OBB)
3134 Slog.i(TAG, "Flushing all OBB state for path " + path);
3135
3136 synchronized (mObbMounts) {
3137 final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
3138
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003139 final Iterator<ObbState> i = mObbPathToStateMap.values().iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003140 while (i.hasNext()) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003141 final ObbState state = i.next();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003142
3143 /*
3144 * If this entry's source file is in the volume path
3145 * that got unmounted, remove it because it's no
3146 * longer valid.
3147 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003148 if (state.canonicalPath.startsWith(path)) {
3149 obbStatesToRemove.add(state);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003150 }
3151 }
3152
3153 for (final ObbState obbState : obbStatesToRemove) {
3154 if (DEBUG_OBB)
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003155 Slog.i(TAG, "Removing state for " + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003156
3157 removeObbStateLocked(obbState);
3158
3159 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003160 obbState.token.onObbResult(obbState.rawPath, obbState.nonce,
Kenny Rootaf9d6672010-10-08 09:21:39 -07003161 OnObbStateChangeListener.UNMOUNTED);
3162 } catch (RemoteException e) {
3163 Slog.i(TAG, "Couldn't send unmount notification for OBB: "
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003164 + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003165 }
3166 }
3167 }
3168 break;
3169 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003170 }
3171 }
3172
3173 private boolean connectToService() {
3174 if (DEBUG_OBB)
3175 Slog.i(TAG, "Trying to bind to DefaultContainerService");
3176
3177 Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Jeff Sharkey6dce4962015-07-03 18:08:41 -07003178 if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE,
Xiaohui Chene4de5a02015-09-22 15:33:31 -07003179 UserHandle.SYSTEM)) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003180 mBound = true;
3181 return true;
3182 }
3183 return false;
3184 }
3185
3186 private void disconnectService() {
3187 mContainerService = null;
3188 mBound = false;
3189 mContext.unbindService(mDefContainerConn);
3190 }
3191 }
3192
3193 abstract class ObbAction {
3194 private static final int MAX_RETRIES = 3;
3195 private int mRetries;
3196
3197 ObbState mObbState;
3198
3199 ObbAction(ObbState obbState) {
3200 mObbState = obbState;
3201 }
3202
3203 public void execute(ObbActionHandler handler) {
3204 try {
3205 if (DEBUG_OBB)
Ben Komalo444eca22011-09-01 15:17:44 -07003206 Slog.i(TAG, "Starting to execute action: " + toString());
Kenny Roota02b8b02010-08-05 16:14:17 -07003207 mRetries++;
3208 if (mRetries > MAX_RETRIES) {
3209 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
Kenny Root480afe72010-10-07 10:17:50 -07003210 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003211 handleError();
Kenny Roota02b8b02010-08-05 16:14:17 -07003212 } else {
3213 handleExecute();
3214 if (DEBUG_OBB)
3215 Slog.i(TAG, "Posting install MCS_UNBIND");
3216 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
3217 }
3218 } catch (RemoteException e) {
3219 if (DEBUG_OBB)
3220 Slog.i(TAG, "Posting install MCS_RECONNECT");
3221 mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
3222 } catch (Exception e) {
3223 if (DEBUG_OBB)
3224 Slog.d(TAG, "Error handling OBB action", e);
3225 handleError();
Kenny Root17eb6fb2010-10-06 15:02:52 -07003226 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003227 }
3228 }
3229
Kenny Root05105f72010-09-22 17:29:43 -07003230 abstract void handleExecute() throws RemoteException, IOException;
Kenny Roota02b8b02010-08-05 16:14:17 -07003231 abstract void handleError();
Kenny Root38cf8862010-09-26 14:18:51 -07003232
3233 protected ObbInfo getObbInfo() throws IOException {
3234 ObbInfo obbInfo;
3235 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003236 obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003237 } catch (RemoteException e) {
3238 Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003239 + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003240 obbInfo = null;
3241 }
3242 if (obbInfo == null) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003243 throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003244 }
3245 return obbInfo;
3246 }
3247
Kenny Rootaf9d6672010-10-08 09:21:39 -07003248 protected void sendNewStatusOrIgnore(int status) {
3249 if (mObbState == null || mObbState.token == null) {
3250 return;
3251 }
3252
Kenny Root38cf8862010-09-26 14:18:51 -07003253 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003254 mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
Kenny Root38cf8862010-09-26 14:18:51 -07003255 } catch (RemoteException e) {
3256 Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
3257 }
3258 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003259 }
3260
3261 class MountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003262 private final String mKey;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003263 private final int mCallingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003264
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003265 MountObbAction(ObbState obbState, String key, int callingUid) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003266 super(obbState);
3267 mKey = key;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003268 mCallingUid = callingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003269 }
3270
Jason parks5af0b912010-11-29 09:05:25 -06003271 @Override
Kenny Root735de3b2010-09-30 14:11:39 -07003272 public void handleExecute() throws IOException, RemoteException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003273 waitForReady();
3274 warnOnNotMounted();
3275
Kenny Root38cf8862010-09-26 14:18:51 -07003276 final ObbInfo obbInfo = getObbInfo();
3277
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003278 if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003279 Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
3280 + " which is owned by " + obbInfo.packageName);
3281 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3282 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003283 }
3284
Kenny Rootaf9d6672010-10-08 09:21:39 -07003285 final boolean isMounted;
3286 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003287 isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003288 }
3289 if (isMounted) {
3290 Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
3291 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
3292 return;
3293 }
3294
Kenny Rootaf9d6672010-10-08 09:21:39 -07003295 final String hashedKey;
3296 if (mKey == null) {
3297 hashedKey = "none";
3298 } else {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003299 try {
Kenny Root3b1abba2010-10-13 15:00:07 -07003300 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
3301
3302 KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
3303 PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
3304 SecretKey key = factory.generateSecret(ks);
3305 BigInteger bi = new BigInteger(key.getEncoded());
3306 hashedKey = bi.toString(16);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003307 } catch (NoSuchAlgorithmException e) {
Kenny Root3b1abba2010-10-13 15:00:07 -07003308 Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
3309 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
3310 return;
3311 } catch (InvalidKeySpecException e) {
3312 Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
3313 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root38cf8862010-09-26 14:18:51 -07003314 return;
3315 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003316 }
Kenny Root38cf8862010-09-26 14:18:51 -07003317
Kenny Rootaf9d6672010-10-08 09:21:39 -07003318 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003319 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003320 mConnector.execute("obb", "mount", mObbState.canonicalPath, new SensitiveArg(hashedKey),
Jeff Sharkey56cd6462013-06-07 15:09:15 -07003321 mObbState.ownerGid);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003322 } catch (NativeDaemonConnectorException e) {
3323 int code = e.getCode();
3324 if (code != VoldResponseCode.OpFailedStorageBusy) {
3325 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003326 }
3327 }
3328
Kenny Rootaf9d6672010-10-08 09:21:39 -07003329 if (rc == StorageResultCode.OperationSucceeded) {
3330 if (DEBUG_OBB)
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003331 Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003332
3333 synchronized (mObbMounts) {
3334 addObbStateLocked(mObbState);
3335 }
3336
3337 sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
Kenny Root02c87302010-07-01 08:10:18 -07003338 } else {
Kenny Root05105f72010-09-22 17:29:43 -07003339 Slog.e(TAG, "Couldn't mount OBB file: " + rc);
Kenny Roota02b8b02010-08-05 16:14:17 -07003340
Kenny Rootaf9d6672010-10-08 09:21:39 -07003341 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
Kenny Root02c87302010-07-01 08:10:18 -07003342 }
3343 }
3344
Jason parks5af0b912010-11-29 09:05:25 -06003345 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003346 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003347 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root02c87302010-07-01 08:10:18 -07003348 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003349
3350 @Override
3351 public String toString() {
3352 StringBuilder sb = new StringBuilder();
3353 sb.append("MountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003354 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003355 sb.append('}');
3356 return sb.toString();
3357 }
3358 }
3359
3360 class UnmountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003361 private final boolean mForceUnmount;
Kenny Roota02b8b02010-08-05 16:14:17 -07003362
3363 UnmountObbAction(ObbState obbState, boolean force) {
3364 super(obbState);
3365 mForceUnmount = force;
3366 }
3367
Jason parks5af0b912010-11-29 09:05:25 -06003368 @Override
Kenny Root38cf8862010-09-26 14:18:51 -07003369 public void handleExecute() throws IOException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003370 waitForReady();
3371 warnOnNotMounted();
3372
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003373 final ObbState existingState;
Kenny Root38cf8862010-09-26 14:18:51 -07003374 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003375 existingState = mObbPathToStateMap.get(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003376 }
Kenny Root38cf8862010-09-26 14:18:51 -07003377
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003378 if (existingState == null) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003379 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
3380 return;
3381 }
3382
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003383 if (existingState.ownerGid != mObbState.ownerGid) {
3384 Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
3385 + " (owned by GID " + existingState.ownerGid + ")");
Kenny Rootaf9d6672010-10-08 09:21:39 -07003386 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3387 return;
3388 }
3389
Kenny Rootaf9d6672010-10-08 09:21:39 -07003390 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003391 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003392 final Command cmd = new Command("obb", "unmount", mObbState.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08003393 if (mForceUnmount) {
3394 cmd.appendArg("force");
3395 }
3396 mConnector.execute(cmd);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003397 } catch (NativeDaemonConnectorException e) {
3398 int code = e.getCode();
3399 if (code == VoldResponseCode.OpFailedStorageBusy) {
3400 rc = StorageResultCode.OperationFailedStorageBusy;
3401 } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
3402 // If it's not mounted then we've already won.
3403 rc = StorageResultCode.OperationSucceeded;
3404 } else {
3405 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003406 }
3407 }
3408
Kenny Rootaf9d6672010-10-08 09:21:39 -07003409 if (rc == StorageResultCode.OperationSucceeded) {
3410 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003411 removeObbStateLocked(existingState);
Kenny Root38cf8862010-09-26 14:18:51 -07003412 }
3413
Kenny Rootaf9d6672010-10-08 09:21:39 -07003414 sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
Kenny Roota02b8b02010-08-05 16:14:17 -07003415 } else {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003416 Slog.w(TAG, "Could not unmount OBB: " + existingState);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003417 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
Kenny Roota02b8b02010-08-05 16:14:17 -07003418 }
3419 }
3420
Jason parks5af0b912010-11-29 09:05:25 -06003421 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003422 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003423 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Roota02b8b02010-08-05 16:14:17 -07003424 }
3425
3426 @Override
3427 public String toString() {
3428 StringBuilder sb = new StringBuilder();
3429 sb.append("UnmountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003430 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003431 sb.append(",force=");
3432 sb.append(mForceUnmount);
Kenny Roota02b8b02010-08-05 16:14:17 -07003433 sb.append('}');
3434 return sb.toString();
3435 }
Kenny Root02c87302010-07-01 08:10:18 -07003436 }
Kenny Root38cf8862010-09-26 14:18:51 -07003437
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003438 private static class Callbacks extends Handler {
3439 private static final int MSG_STORAGE_STATE_CHANGED = 1;
3440 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003441 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
3442 private static final int MSG_VOLUME_FORGOTTEN = 4;
3443 private static final int MSG_DISK_SCANNED = 5;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003444 private static final int MSG_DISK_DESTROYED = 6;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003445
3446 private final RemoteCallbackList<IMountServiceListener>
3447 mCallbacks = new RemoteCallbackList<>();
3448
3449 public Callbacks(Looper looper) {
3450 super(looper);
3451 }
3452
3453 public void register(IMountServiceListener callback) {
3454 mCallbacks.register(callback);
3455 }
3456
3457 public void unregister(IMountServiceListener callback) {
3458 mCallbacks.unregister(callback);
3459 }
3460
3461 @Override
3462 public void handleMessage(Message msg) {
3463 final SomeArgs args = (SomeArgs) msg.obj;
3464 final int n = mCallbacks.beginBroadcast();
3465 for (int i = 0; i < n; i++) {
3466 final IMountServiceListener callback = mCallbacks.getBroadcastItem(i);
3467 try {
3468 invokeCallback(callback, msg.what, args);
3469 } catch (RemoteException ignored) {
3470 }
3471 }
3472 mCallbacks.finishBroadcast();
3473 args.recycle();
3474 }
3475
3476 private void invokeCallback(IMountServiceListener callback, int what, SomeArgs args)
3477 throws RemoteException {
3478 switch (what) {
3479 case MSG_STORAGE_STATE_CHANGED: {
3480 callback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
3481 (String) args.arg3);
3482 break;
3483 }
3484 case MSG_VOLUME_STATE_CHANGED: {
3485 callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
3486 break;
3487 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07003488 case MSG_VOLUME_RECORD_CHANGED: {
3489 callback.onVolumeRecordChanged((VolumeRecord) args.arg1);
3490 break;
3491 }
3492 case MSG_VOLUME_FORGOTTEN: {
3493 callback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003494 break;
3495 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003496 case MSG_DISK_SCANNED: {
3497 callback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003498 break;
3499 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003500 case MSG_DISK_DESTROYED: {
3501 callback.onDiskDestroyed((DiskInfo) args.arg1);
3502 break;
3503 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003504 }
3505 }
3506
3507 private void notifyStorageStateChanged(String path, String oldState, String newState) {
3508 final SomeArgs args = SomeArgs.obtain();
3509 args.arg1 = path;
3510 args.arg2 = oldState;
3511 args.arg3 = newState;
3512 obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
3513 }
3514
3515 private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
3516 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003517 args.arg1 = vol.clone();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003518 args.argi2 = oldState;
3519 args.argi3 = newState;
3520 obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
3521 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003522
Jeff Sharkey50a05452015-04-29 11:24:52 -07003523 private void notifyVolumeRecordChanged(VolumeRecord rec) {
3524 final SomeArgs args = SomeArgs.obtain();
3525 args.arg1 = rec.clone();
3526 obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
3527 }
3528
3529 private void notifyVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003530 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003531 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003532 obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003533 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003534
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003535 private void notifyDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003536 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003537 args.arg1 = disk.clone();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003538 args.argi2 = volumeCount;
3539 obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003540 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003541
3542 private void notifyDiskDestroyed(DiskInfo disk) {
3543 final SomeArgs args = SomeArgs.obtain();
3544 args.arg1 = disk.clone();
3545 obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
3546 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003547 }
3548
Kenny Root38cf8862010-09-26 14:18:51 -07003549 @Override
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003550 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
3551 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
3552
3553 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003554 synchronized (mLock) {
3555 pw.println("Disks:");
3556 pw.increaseIndent();
3557 for (int i = 0; i < mDisks.size(); i++) {
3558 final DiskInfo disk = mDisks.valueAt(i);
3559 disk.dump(pw);
3560 }
3561 pw.decreaseIndent();
3562
3563 pw.println();
3564 pw.println("Volumes:");
3565 pw.increaseIndent();
3566 for (int i = 0; i < mVolumes.size(); i++) {
3567 final VolumeInfo vol = mVolumes.valueAt(i);
3568 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue;
3569 vol.dump(pw);
3570 }
3571 pw.decreaseIndent();
3572
3573 pw.println();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003574 pw.println("Records:");
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003575 pw.increaseIndent();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003576 for (int i = 0; i < mRecords.size(); i++) {
3577 final VolumeRecord note = mRecords.valueAt(i);
3578 note.dump(pw);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003579 }
3580 pw.decreaseIndent();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07003581
3582 pw.println();
3583 pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07003584 pw.println("Force adoptable: " + mForceAdoptable);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08003585 pw.println();
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003586 pw.println("Local unlocked users: " + Arrays.toString(mLocalUnlockedUsers));
3587 pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003588 }
Kenny Root38cf8862010-09-26 14:18:51 -07003589
Kenny Root38cf8862010-09-26 14:18:51 -07003590 synchronized (mObbMounts) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003591 pw.println();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003592 pw.println("mObbMounts:");
3593 pw.increaseIndent();
3594 final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet()
3595 .iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003596 while (binders.hasNext()) {
3597 Entry<IBinder, List<ObbState>> e = binders.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003598 pw.println(e.getKey() + ":");
3599 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003600 final List<ObbState> obbStates = e.getValue();
Kenny Root38cf8862010-09-26 14:18:51 -07003601 for (final ObbState obbState : obbStates) {
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003602 pw.println(obbState);
Kenny Root38cf8862010-09-26 14:18:51 -07003603 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003604 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003605 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003606 pw.decreaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003607
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003608 pw.println();
3609 pw.println("mObbPathToStateMap:");
3610 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003611 final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
3612 while (maps.hasNext()) {
3613 final Entry<String, ObbState> e = maps.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003614 pw.print(e.getKey());
3615 pw.print(" -> ");
3616 pw.println(e.getValue());
Kenny Rootaf9d6672010-10-08 09:21:39 -07003617 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003618 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003619 }
Kenny Root4161f9b2011-07-13 09:48:33 -07003620
Robert Greenwalt470fd722012-01-18 12:51:15 -08003621 pw.println();
Jeff Sharkey5b0e5202015-12-18 17:18:09 -07003622 pw.println("mConnector:");
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003623 pw.increaseIndent();
Robert Greenwalt470fd722012-01-18 12:51:15 -08003624 mConnector.dump(fd, pw, args);
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003625 pw.decreaseIndent();
Christopher Tate7265abe2014-11-21 13:54:45 -08003626
Christopher Tate7265abe2014-11-21 13:54:45 -08003627 pw.println();
Jeff Sharkey5b0e5202015-12-18 17:18:09 -07003628 pw.println("mCryptConnector:");
3629 pw.increaseIndent();
3630 mCryptConnector.dump(fd, pw, args);
3631 pw.decreaseIndent();
3632
3633 pw.println();
Christopher Tate7265abe2014-11-21 13:54:45 -08003634 pw.print("Last maintenance: ");
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07003635 pw.println(TimeUtils.formatForLogging(mLastMaintenance));
Kenny Root38cf8862010-09-26 14:18:51 -07003636 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003637
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003638 /** {@inheritDoc} */
Jeff Sharkey48877892015-03-18 11:27:19 -07003639 @Override
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003640 public void monitor() {
3641 if (mConnector != null) {
3642 mConnector.monitor();
3643 }
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07003644 if (mCryptConnector != null) {
3645 mCryptConnector.monitor();
3646 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003647 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003648
3649 private final class MountServiceInternalImpl extends MountServiceInternal {
3650 // Not guarded by a lock.
3651 private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
3652 new CopyOnWriteArrayList<>();
3653
3654 @Override
3655 public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
3656 // No locking - CopyOnWriteArrayList
3657 mPolicies.add(policy);
3658 }
3659
3660 @Override
3661 public void onExternalStoragePolicyChanged(int uid, String packageName) {
3662 final int mountMode = getExternalStorageMountMode(uid, packageName);
3663 remountUidExternalStorage(uid, mountMode);
3664 }
3665
3666 @Override
3667 public int getExternalStorageMountMode(int uid, String packageName) {
3668 // No locking - CopyOnWriteArrayList
3669 int mountMode = Integer.MAX_VALUE;
3670 for (ExternalStorageMountPolicy policy : mPolicies) {
3671 final int policyMode = policy.getMountMode(uid, packageName);
3672 if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
3673 return Zygote.MOUNT_EXTERNAL_NONE;
3674 }
3675 mountMode = Math.min(mountMode, policyMode);
3676 }
3677 if (mountMode == Integer.MAX_VALUE) {
3678 return Zygote.MOUNT_EXTERNAL_NONE;
3679 }
3680 return mountMode;
3681 }
3682
3683 public boolean hasExternalStorage(int uid, String packageName) {
Amith Yamasani2bd5cff2015-07-22 14:42:31 -07003684 // No need to check for system uid. This avoids a deadlock between
3685 // PackageManagerService and AppOpsService.
3686 if (uid == Process.SYSTEM_UID) {
3687 return true;
3688 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003689 // No locking - CopyOnWriteArrayList
3690 for (ExternalStorageMountPolicy policy : mPolicies) {
3691 final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
3692 if (!policyHasStorage) {
3693 return false;
3694 }
3695 }
3696 return true;
3697 }
3698 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003699}