blob: ccca5baa798a3fa5cf10983069375187d8cbc146 [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,
Jeff Sharkey8a372a02016-03-16 16:25:45 -0600812 PackageManager.MATCH_DIRECT_BOOT_AWARE
813 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
814 user.id);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700815 if (provider != null) {
816 final IActivityManager am = ActivityManagerNative.getDefault();
817 try {
818 am.killApplicationWithAppId(provider.applicationInfo.packageName,
819 UserHandle.getAppId(provider.applicationInfo.uid), "vold reset");
820 // We only need to run this once. It will kill all users' media processes.
821 break;
822 } catch (RemoteException e) {
823 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700824 }
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700825 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700826 } finally {
827 Binder.restoreCallingIdentity(token);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700828 }
829 }
830
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800831 private void addInternalVolumeLocked() {
Amith Yamasania7892482015-08-07 11:09:05 -0700832 // Create a stub volume that represents internal storage
833 final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
834 VolumeInfo.TYPE_PRIVATE, null, null);
835 internal.state = VolumeInfo.STATE_MOUNTED;
836 internal.path = Environment.getDataDirectory().getAbsolutePath();
837 mVolumes.put(internal.id, internal);
838 }
839
Jeff Sharkey8924e872015-11-30 12:52:10 -0700840 private void initIfReadyAndConnected() {
841 Slog.d(TAG, "Thinking about init, mSystemReady=" + mSystemReady
842 + ", mDaemonConnected=" + mDaemonConnected);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700843 if (mSystemReady && mDaemonConnected
Paul Lawrence20be5d62016-02-26 13:51:17 -0800844 && !StorageManager.isFileEncryptedNativeOnly()) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700845 // When booting a device without native support, make sure that our
846 // user directories are locked or unlocked based on the current
847 // emulation status.
Paul Lawrence20be5d62016-02-26 13:51:17 -0800848 final boolean initLocked = StorageManager.isFileEncryptedEmulatedOnly();
Paul Crowleyd94ab732016-02-15 06:44:51 +0000849 Slog.d(TAG, "Setting up emulation state, initlocked=" + initLocked);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700850 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Jeff Sharkey8924e872015-11-30 12:52:10 -0700851 for (UserInfo user : users) {
852 try {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700853 if (initLocked) {
854 mCryptConnector.execute("cryptfs", "lock_user_key", user.id);
855 } else {
856 mCryptConnector.execute("cryptfs", "unlock_user_key", user.id,
Paul Crowleyd94ab732016-02-15 06:44:51 +0000857 user.serialNumber, "!", "!");
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700858 }
Jeff Sharkey8924e872015-11-30 12:52:10 -0700859 } catch (NativeDaemonConnectorException e) {
860 Slog.w(TAG, "Failed to init vold", e);
861 }
862 }
863 }
864 }
865
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800866 private void resetIfReadyAndConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700867 Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
868 + ", mDaemonConnected=" + mDaemonConnected);
869 if (mSystemReady && mDaemonConnected) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800870 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700871 killMediaProvider(users);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700872
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700873 final int[] systemUnlockedUsers;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800874 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700875 systemUnlockedUsers = mSystemUnlockedUsers;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700876
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800877 mDisks.clear();
878 mVolumes.clear();
879
880 addInternalVolumeLocked();
881 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700882
Jeff Sharkey48877892015-03-18 11:27:19 -0700883 try {
884 mConnector.execute("volume", "reset");
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700885
886 // Tell vold about all existing and started users
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700887 for (UserInfo user : users) {
888 mConnector.execute("volume", "user_added", user.id, user.serialNumber);
889 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700890 for (int userId : systemUnlockedUsers) {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700891 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey50a05452015-04-29 11:24:52 -0700892 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700893 } catch (NativeDaemonConnectorException e) {
894 Slog.w(TAG, "Failed to reset vold", e);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700895 }
896 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700897 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700898
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700899 private void onUnlockUser(int userId) {
900 Slog.d(TAG, "onUnlockUser " + userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700901
902 // We purposefully block here to make sure that user-specific
903 // staging area is ready so it's ready for zygote-forked apps to
904 // bind mount against.
905 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700906 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700907 } catch (NativeDaemonConnectorException ignored) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700908 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700909
910 // Record user as started so newly mounted volumes kick off events
911 // correctly, then synthesize events for any already-mounted volumes.
912 synchronized (mVolumes) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700913 for (int i = 0; i < mVolumes.size(); i++) {
914 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey46349872015-07-28 10:49:47 -0700915 if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700916 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey48877892015-03-18 11:27:19 -0700917 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700918
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700919 final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
920 mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700921 }
922 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700923 mSystemUnlockedUsers = ArrayUtils.appendInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700924 }
925 }
926
927 private void onCleanupUser(int userId) {
928 Slog.d(TAG, "onCleanupUser " + userId);
929
930 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700931 mConnector.execute("volume", "user_stopped", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700932 } catch (NativeDaemonConnectorException ignored) {
933 }
934
935 synchronized (mVolumes) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700936 mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700937 }
938 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700939
Christopher Tated417d622013-08-19 16:14:25 -0700940 void runIdleMaintenance(Runnable callback) {
941 mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
942 }
943
Christopher Tate7265abe2014-11-21 13:54:45 -0800944 // Binder entry point for kicking off an immediate fstrim
945 @Override
946 public void runMaintenance() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700947 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Christopher Tate7265abe2014-11-21 13:54:45 -0800948 runIdleMaintenance(null);
949 }
950
951 @Override
952 public long lastMaintenance() {
953 return mLastMaintenance;
954 }
955
San Mehat4270e1e2010-01-29 05:32:19 -0800956 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800957 * Callback from NativeDaemonConnector
958 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700959 @Override
San Mehat4270e1e2010-01-29 05:32:19 -0800960 public void onDaemonConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700961 mDaemonConnected = true;
962 mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();
963 }
964
965 private void handleDaemonConnected() {
Jeff Sharkey8924e872015-11-30 12:52:10 -0700966 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800967 resetIfReadyAndConnected();
Jeff Sharkey48877892015-03-18 11:27:19 -0700968
San Mehat4270e1e2010-01-29 05:32:19 -0800969 /*
Jeff Sharkey48877892015-03-18 11:27:19 -0700970 * Now that we've done our initialization, release
971 * the hounds!
San Mehat4270e1e2010-01-29 05:32:19 -0800972 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700973 mConnectedSignal.countDown();
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700974 if (mConnectedSignal.getCount() != 0) {
975 // More daemons need to connect
976 return;
977 }
Mike Lockwood7fa24aa2011-03-23 14:52:34 -0400978
Jeff Sharkey48877892015-03-18 11:27:19 -0700979 // On an encrypted device we can't see system properties yet, so pull
980 // the system locale out of the mount service.
981 if ("".equals(SystemProperties.get("vold.encrypt_progress"))) {
982 copyLocaleFromMountService();
983 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700984
Jeff Sharkey48877892015-03-18 11:27:19 -0700985 // Let package manager load internal ASECs.
986 mPms.scanAvailableAsecs();
Mike Lockwood7fa24aa2011-03-23 14:52:34 -0400987
Jeff Sharkey48877892015-03-18 11:27:19 -0700988 // Notify people waiting for ASECs to be scanned that it's done.
989 mAsecsScanned.countDown();
San Mehat4270e1e2010-01-29 05:32:19 -0800990 }
991
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700992 private void copyLocaleFromMountService() {
993 String systemLocale;
994 try {
995 systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
996 } catch (RemoteException e) {
997 return;
998 }
999 if (TextUtils.isEmpty(systemLocale)) {
1000 return;
1001 }
1002
1003 Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
1004 Locale locale = Locale.forLanguageTag(systemLocale);
1005 Configuration config = new Configuration();
1006 config.setLocale(locale);
1007 try {
1008 ActivityManagerNative.getDefault().updateConfiguration(config);
1009 } catch (RemoteException e) {
1010 Slog.e(TAG, "Error setting system locale from mount service", e);
1011 }
Elliott Hughes9c33f282014-10-13 12:39:56 -07001012
1013 // Temporary workaround for http://b/17945169.
1014 Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
Narayan Kamathd30dbb82015-01-15 14:48:15 +00001015 SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001016 }
1017
San Mehat4270e1e2010-01-29 05:32:19 -08001018 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001019 * Callback from NativeDaemonConnector
1020 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001021 @Override
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001022 public boolean onCheckHoldWakeLock(int code) {
1023 return false;
1024 }
1025
1026 /**
1027 * Callback from NativeDaemonConnector
1028 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001029 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001030 public boolean onEvent(int code, String raw, String[] cooked) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001031 synchronized (mLock) {
1032 return onEventLocked(code, raw, cooked);
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -08001033 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001034 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001035
Jeff Sharkey48877892015-03-18 11:27:19 -07001036 private boolean onEventLocked(int code, String raw, String[] cooked) {
1037 switch (code) {
1038 case VoldResponseCode.DISK_CREATED: {
1039 if (cooked.length != 3) break;
1040 final String id = cooked[1];
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001041 int flags = Integer.parseInt(cooked[2]);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001042 if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false)
1043 || mForceAdoptable) {
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001044 flags |= DiskInfo.FLAG_ADOPTABLE;
1045 }
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001046 mDisks.put(id, new DiskInfo(id, flags));
Jeff Sharkey48877892015-03-18 11:27:19 -07001047 break;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001048 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001049 case VoldResponseCode.DISK_SIZE_CHANGED: {
1050 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001051 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001052 if (disk != null) {
1053 disk.size = Long.parseLong(cooked[2]);
San Mehat4270e1e2010-01-29 05:32:19 -08001054 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001055 break;
1056 }
1057 case VoldResponseCode.DISK_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001058 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001059 if (disk != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001060 final StringBuilder builder = new StringBuilder();
1061 for (int i = 2; i < cooked.length; i++) {
1062 builder.append(cooked[i]).append(' ');
1063 }
1064 disk.label = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001065 }
1066 break;
1067 }
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001068 case VoldResponseCode.DISK_SCANNED: {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001069 if (cooked.length != 2) break;
1070 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001071 if (disk != null) {
1072 onDiskScannedLocked(disk);
1073 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -07001074 break;
1075 }
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001076 case VoldResponseCode.DISK_SYS_PATH_CHANGED: {
1077 if (cooked.length != 3) break;
1078 final DiskInfo disk = mDisks.get(cooked[1]);
1079 if (disk != null) {
1080 disk.sysPath = cooked[2];
1081 }
1082 break;
1083 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001084 case VoldResponseCode.DISK_DESTROYED: {
1085 if (cooked.length != 2) break;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07001086 final DiskInfo disk = mDisks.remove(cooked[1]);
1087 if (disk != null) {
1088 mCallbacks.notifyDiskDestroyed(disk);
1089 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001090 break;
1091 }
San Mehat4270e1e2010-01-29 05:32:19 -08001092
Jeff Sharkey48877892015-03-18 11:27:19 -07001093 case VoldResponseCode.VOLUME_CREATED: {
Jeff Sharkey48877892015-03-18 11:27:19 -07001094 final String id = cooked[1];
1095 final int type = Integer.parseInt(cooked[2]);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001096 final String diskId = TextUtils.nullIfEmpty(cooked[3]);
1097 final String partGuid = TextUtils.nullIfEmpty(cooked[4]);
1098
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001099 final DiskInfo disk = mDisks.get(diskId);
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07001100 final VolumeInfo vol = new VolumeInfo(id, type, disk, partGuid);
Jeff Sharkey48877892015-03-18 11:27:19 -07001101 mVolumes.put(id, vol);
1102 onVolumeCreatedLocked(vol);
1103 break;
1104 }
1105 case VoldResponseCode.VOLUME_STATE_CHANGED: {
1106 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001107 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001108 if (vol != null) {
1109 final int oldState = vol.state;
1110 final int newState = Integer.parseInt(cooked[2]);
1111 vol.state = newState;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001112 onVolumeStateChangedLocked(vol, oldState, newState);
Jeff Sharkey48877892015-03-18 11:27:19 -07001113 }
1114 break;
1115 }
1116 case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: {
1117 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001118 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001119 if (vol != null) {
1120 vol.fsType = cooked[2];
1121 }
1122 break;
1123 }
1124 case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
1125 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001126 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001127 if (vol != null) {
1128 vol.fsUuid = cooked[2];
1129 }
1130 break;
1131 }
1132 case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001133 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001134 if (vol != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001135 final StringBuilder builder = new StringBuilder();
1136 for (int i = 2; i < cooked.length; i++) {
1137 builder.append(cooked[i]).append(' ');
1138 }
1139 vol.fsLabel = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001140 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001141 // TODO: notify listeners that label changed
Jeff Sharkey48877892015-03-18 11:27:19 -07001142 break;
1143 }
1144 case VoldResponseCode.VOLUME_PATH_CHANGED: {
1145 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001146 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001147 if (vol != null) {
1148 vol.path = cooked[2];
1149 }
1150 break;
1151 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001152 case VoldResponseCode.VOLUME_INTERNAL_PATH_CHANGED: {
1153 if (cooked.length != 3) break;
1154 final VolumeInfo vol = mVolumes.get(cooked[1]);
1155 if (vol != null) {
1156 vol.internalPath = cooked[2];
1157 }
1158 break;
1159 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001160 case VoldResponseCode.VOLUME_DESTROYED: {
1161 if (cooked.length != 2) break;
1162 mVolumes.remove(cooked[1]);
1163 break;
1164 }
San Mehat4270e1e2010-01-29 05:32:19 -08001165
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001166 case VoldResponseCode.MOVE_STATUS: {
1167 final int status = Integer.parseInt(cooked[1]);
1168 onMoveStatusLocked(status);
1169 break;
1170 }
Jeff Sharkey9756d752015-05-14 21:07:42 -07001171 case VoldResponseCode.BENCHMARK_RESULT: {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001172 if (cooked.length != 7) break;
1173 final String path = cooked[1];
1174 final String ident = cooked[2];
1175 final long create = Long.parseLong(cooked[3]);
1176 final long drop = Long.parseLong(cooked[4]);
1177 final long run = Long.parseLong(cooked[5]);
1178 final long destroy = Long.parseLong(cooked[6]);
1179
Jeff Sharkey9756d752015-05-14 21:07:42 -07001180 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001181 dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
1182 + " " + ident + " " + create + " " + run + " " + destroy);
1183
1184 final VolumeRecord rec = findRecordForPath(path);
1185 if (rec != null) {
1186 rec.lastBenchMillis = System.currentTimeMillis();
1187 writeSettingsLocked();
1188 }
1189
1190 break;
1191 }
1192 case VoldResponseCode.TRIM_RESULT: {
1193 if (cooked.length != 4) break;
1194 final String path = cooked[1];
1195 final long bytes = Long.parseLong(cooked[2]);
1196 final long time = Long.parseLong(cooked[3]);
1197
1198 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
1199 dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path)
1200 + " " + bytes + " " + time);
1201
1202 final VolumeRecord rec = findRecordForPath(path);
1203 if (rec != null) {
1204 rec.lastTrimMillis = System.currentTimeMillis();
1205 writeSettingsLocked();
1206 }
1207
Jeff Sharkey9756d752015-05-14 21:07:42 -07001208 break;
1209 }
1210
Jeff Sharkey48877892015-03-18 11:27:19 -07001211 default: {
1212 Slog.d(TAG, "Unhandled vold event " + code);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001213 }
San Mehat4270e1e2010-01-29 05:32:19 -08001214 }
1215
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001216 return true;
San Mehat4270e1e2010-01-29 05:32:19 -08001217 }
1218
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001219 private void onDiskScannedLocked(DiskInfo disk) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001220 int volumeCount = 0;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001221 for (int i = 0; i < mVolumes.size(); i++) {
1222 final VolumeInfo vol = mVolumes.valueAt(i);
1223 if (Objects.equals(disk.id, vol.getDiskId())) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001224 volumeCount++;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001225 }
1226 }
1227
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001228 final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
1229 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1230 intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
1231 intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001232 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001233
1234 final CountDownLatch latch = mDiskScanLatches.remove(disk.id);
1235 if (latch != null) {
1236 latch.countDown();
1237 }
1238
Jeff Sharkeyf5a6bd72015-05-19 14:42:38 -07001239 disk.volumeCount = volumeCount;
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001240 mCallbacks.notifyDiskScanned(disk, volumeCount);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001241 }
1242
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001243 private void onVolumeCreatedLocked(VolumeInfo vol) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001244 if (vol.type == VolumeInfo.TYPE_EMULATED) {
1245 final StorageManager storage = mContext.getSystemService(StorageManager.class);
1246 final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
1247
1248 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
1249 && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
1250 Slog.v(TAG, "Found primary storage at " + vol);
1251 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1252 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1253 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1254
1255 } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
1256 Slog.v(TAG, "Found primary storage at " + vol);
1257 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1258 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1259 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1260 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001261
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001262 } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001263 // TODO: only look at first public partition
1264 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1265 && vol.disk.isDefaultPrimary()) {
1266 Slog.v(TAG, "Found primary storage at " + vol);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001267 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1268 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
San Mehat4270e1e2010-01-29 05:32:19 -08001269 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001270
1271 // Adoptable public disks are visible to apps, since they meet
1272 // public API requirement of being in a stable location.
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001273 if (vol.disk.isAdoptable()) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001274 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1275 }
1276
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07001277 vol.mountUserId = ActivityManager.getCurrentUser();
Jeff Sharkey48877892015-03-18 11:27:19 -07001278 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001279
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001280 } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1281 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1282
San Mehat4270e1e2010-01-29 05:32:19 -08001283 } else {
Jeff Sharkey48877892015-03-18 11:27:19 -07001284 Slog.d(TAG, "Skipping automatic mounting of " + vol);
San Mehat4270e1e2010-01-29 05:32:19 -08001285 }
1286 }
1287
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001288 private boolean isBroadcastWorthy(VolumeInfo vol) {
1289 switch (vol.getType()) {
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001290 case VolumeInfo.TYPE_PRIVATE:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001291 case VolumeInfo.TYPE_PUBLIC:
1292 case VolumeInfo.TYPE_EMULATED:
1293 break;
1294 default:
1295 return false;
1296 }
1297
1298 switch (vol.getState()) {
1299 case VolumeInfo.STATE_MOUNTED:
1300 case VolumeInfo.STATE_MOUNTED_READ_ONLY:
1301 case VolumeInfo.STATE_EJECTING:
1302 case VolumeInfo.STATE_UNMOUNTED:
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001303 case VolumeInfo.STATE_UNMOUNTABLE:
Tony Mantlerf0d71052015-06-24 11:45:25 -07001304 case VolumeInfo.STATE_BAD_REMOVAL:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001305 break;
1306 default:
1307 return false;
1308 }
1309
1310 return true;
1311 }
1312
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001313 private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001314 // Remember that we saw this volume so we're ready to accept user
1315 // metadata, or so we can annoy them when a private volume is ejected
1316 if (vol.isMountedReadable() && !TextUtils.isEmpty(vol.fsUuid)) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001317 VolumeRecord rec = mRecords.get(vol.fsUuid);
1318 if (rec == null) {
1319 rec = new VolumeRecord(vol.type, vol.fsUuid);
1320 rec.partGuid = vol.partGuid;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001321 rec.createdMillis = System.currentTimeMillis();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001322 if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1323 rec.nickname = vol.disk.getDescription();
1324 }
1325 mRecords.put(rec.fsUuid, rec);
1326 writeSettingsLocked();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001327 } else {
1328 // Handle upgrade case where we didn't store partition GUID
1329 if (TextUtils.isEmpty(rec.partGuid)) {
1330 rec.partGuid = vol.partGuid;
1331 writeSettingsLocked();
1332 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001333 }
1334 }
1335
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001336 mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
1337
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001338 // Do not broadcast before boot has completed to avoid launching the
1339 // processes that receive the intent unnecessarily.
1340 if (mBootCompleted && isBroadcastWorthy(vol)) {
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001341 final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001342 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
1343 intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
Tony Mantlerf0d71052015-06-24 11:45:25 -07001344 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001345 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001346 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001347 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001348
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001349 final String oldStateEnv = VolumeInfo.getEnvironmentForState(oldState);
1350 final String newStateEnv = VolumeInfo.getEnvironmentForState(newState);
Emily Bernier92aa5a22014-07-07 10:11:48 -04001351
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001352 if (!Objects.equals(oldStateEnv, newStateEnv)) {
1353 // Kick state changed event towards all started users. Any users
1354 // started after this point will trigger additional
1355 // user-specific broadcasts.
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001356 for (int userId : mSystemUnlockedUsers) {
Jeff Sharkey46349872015-07-28 10:49:47 -07001357 if (vol.isVisibleForRead(userId)) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001358 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001359 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey48877892015-03-18 11:27:19 -07001360
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001361 mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
1362 newStateEnv);
San Mehat4270e1e2010-01-29 05:32:19 -08001363 }
1364 }
1365 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001366
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001367 if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.state == VolumeInfo.STATE_EJECTING) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001368 // TODO: this should eventually be handled by new ObbVolume state changes
1369 /*
1370 * Some OBBs might have been unmounted when this volume was
1371 * unmounted, so send a message to the handler to let it know to
1372 * remove those from the list of mounted OBBS.
1373 */
1374 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
1375 OBB_FLUSH_MOUNT_STATE, vol.path));
1376 }
San Mehat4270e1e2010-01-29 05:32:19 -08001377 }
1378
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001379 private void onMoveStatusLocked(int status) {
1380 if (mMoveCallback == null) {
1381 Slog.w(TAG, "Odd, status but no move requested");
1382 return;
1383 }
1384
1385 // TODO: estimate remaining time
1386 try {
Jeff Sharkey50a05452015-04-29 11:24:52 -07001387 mMoveCallback.onStatusChanged(-1, status, -1);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001388 } catch (RemoteException ignored) {
1389 }
1390
1391 // We've finished copying and we're about to clean up old data, so
1392 // remember that move was successful if we get rebooted
1393 if (status == MOVE_STATUS_COPY_FINISHED) {
1394 Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
1395
1396 mPrimaryStorageUuid = mMoveTargetUuid;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001397 writeSettingsLocked();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001398 }
1399
1400 if (PackageManager.isMoveStatusFinished(status)) {
1401 Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status);
1402
1403 mMoveCallback = null;
1404 mMoveTargetUuid = null;
1405 }
1406 }
1407
Jeff Sharkey48877892015-03-18 11:27:19 -07001408 private void enforcePermission(String perm) {
1409 mContext.enforceCallingOrSelfPermission(perm, perm);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001410 }
1411
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001412 /**
1413 * Decide if volume is mountable per device policies.
1414 */
1415 private boolean isMountDisallowed(VolumeInfo vol) {
1416 if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
1417 final UserManager userManager = mContext.getSystemService(UserManager.class);
1418 return userManager.hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
1419 Binder.getCallingUserHandle());
1420 } else {
1421 return false;
Emily Bernier92aa5a22014-07-07 10:11:48 -04001422 }
1423 }
1424
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001425 private void enforceAdminUser() {
1426 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1427 final int callingUserId = UserHandle.getCallingUserId();
1428 boolean isAdmin;
1429 long token = Binder.clearCallingIdentity();
1430 try {
1431 isAdmin = um.getUserInfo(callingUserId).isAdmin();
1432 } finally {
1433 Binder.restoreCallingIdentity(token);
1434 }
1435 if (!isAdmin) {
1436 throw new SecurityException("Only admin users can adopt sd cards");
1437 }
1438 }
1439
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001440 /**
San Mehat207e5382010-02-04 20:46:54 -08001441 * Constructs a new MountService instance
1442 *
1443 * @param context Binder context for this service
1444 */
1445 public MountService(Context context) {
Christopher Tated417d622013-08-19 16:14:25 -07001446 sSelf = this;
1447
San Mehat207e5382010-02-04 20:46:54 -08001448 mContext = context;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001449 mCallbacks = new Callbacks(FgThread.get().getLooper());
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001450 mLockPatternUtils = new LockPatternUtils(mContext);
San Mehat207e5382010-02-04 20:46:54 -08001451
San Mehat207e5382010-02-04 20:46:54 -08001452 // XXX: This will go away soon in favor of IMountServiceObserver
1453 mPms = (PackageManagerService) ServiceManager.getService("package");
1454
Dianne Hackbornefa92b22013-05-03 14:11:43 -07001455 HandlerThread hthread = new HandlerThread(TAG);
1456 hthread.start();
1457 mHandler = new MountServiceHandler(hthread.getLooper());
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001458
Kenny Roota02b8b02010-08-05 16:14:17 -07001459 // Add OBB Action Handler to MountService thread.
Dianne Hackborn8d044e82013-04-30 17:24:15 -07001460 mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
Kenny Roota02b8b02010-08-05 16:14:17 -07001461
Christopher Tate7265abe2014-11-21 13:54:45 -08001462 // Initialize the last-fstrim tracking if necessary
1463 File dataDir = Environment.getDataDirectory();
1464 File systemDir = new File(dataDir, "system");
1465 mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
1466 if (!mLastMaintenanceFile.exists()) {
1467 // Not setting mLastMaintenance here means that we will force an
1468 // fstrim during reboot following the OTA that installs this code.
1469 try {
1470 (new FileOutputStream(mLastMaintenanceFile)).close();
1471 } catch (IOException e) {
1472 Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
1473 }
1474 } else {
1475 mLastMaintenance = mLastMaintenanceFile.lastModified();
1476 }
1477
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001478 mSettingsFile = new AtomicFile(
Jeff Sharkey8212ae02016-02-10 14:46:43 -07001479 new File(Environment.getDataSystemDirectory(), "storage.xml"));
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001480
1481 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001482 readSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001483 }
1484
Svet Ganov6ee871e2015-07-10 14:29:33 -07001485 LocalServices.addService(MountServiceInternal.class, mMountServiceInternal);
1486
Marco Nelissenc34ebce2010-02-18 13:39:41 -08001487 /*
Kenny Root305bcbf2010-09-03 07:56:38 -07001488 * Create the connection to vold with a maximum queue of twice the
1489 * amount of containers we'd ever expect to have. This keeps an
1490 * "asec list" from blocking a thread repeatedly.
1491 */
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001492
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001493 mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
1494 null);
Jeff Sharkey48877892015-03-18 11:27:19 -07001495 mConnector.setDebug(true);
Jeff Sharkey8948c012015-11-03 12:33:54 -08001496 mConnector.setWarnIfHeld(mLock);
Kenny Root51a573c2012-05-17 13:30:28 -07001497
Kenny Root305bcbf2010-09-03 07:56:38 -07001498 Thread thread = new Thread(mConnector, VOLD_TAG);
San Mehat207e5382010-02-04 20:46:54 -08001499 thread.start();
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07001500
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001501 // Reuse parameters from first connector since they are tested and safe
1502 mCryptConnector = new NativeDaemonConnector(this, "cryptd",
1503 MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
1504 mCryptConnector.setDebug(true);
1505
1506 Thread crypt_thread = new Thread(mCryptConnector, CRYPTD_TAG);
1507 crypt_thread.start();
1508
Jeff Sharkeybcd262d2015-06-10 09:41:17 -07001509 final IntentFilter userFilter = new IntentFilter();
1510 userFilter.addAction(Intent.ACTION_USER_ADDED);
1511 userFilter.addAction(Intent.ACTION_USER_REMOVED);
1512 mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
1513
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001514 synchronized (mLock) {
1515 addInternalVolumeLocked();
1516 }
Amith Yamasania7892482015-08-07 11:09:05 -07001517
Kenny Root07714d42011-08-17 17:49:28 -07001518 // Add ourself to the Watchdog monitors if enabled.
1519 if (WATCHDOG_ENABLE) {
1520 Watchdog.getInstance().addMonitor(this);
1521 }
San Mehat207e5382010-02-04 20:46:54 -08001522 }
1523
Jeff Sharkey56e62932015-03-21 20:41:00 -07001524 private void systemReady() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001525 mSystemReady = true;
1526 mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
1527 }
1528
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001529 private void bootCompleted() {
1530 mBootCompleted = true;
1531 }
1532
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001533 private String getDefaultPrimaryStorageUuid() {
1534 if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) {
1535 return StorageManager.UUID_PRIMARY_PHYSICAL;
1536 } else {
1537 return StorageManager.UUID_PRIVATE_INTERNAL;
1538 }
1539 }
1540
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001541 private void readSettingsLocked() {
1542 mRecords.clear();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001543 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001544 mForceAdoptable = false;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001545
1546 FileInputStream fis = null;
1547 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001548 fis = mSettingsFile.openRead();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001549 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001550 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001551
1552 int type;
1553 while ((type = in.next()) != END_DOCUMENT) {
1554 if (type == START_TAG) {
1555 final String tag = in.getName();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001556 if (TAG_VOLUMES.equals(tag)) {
1557 final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001558 final boolean primaryPhysical = SystemProperties.getBoolean(
1559 StorageManager.PROP_PRIMARY_PHYSICAL, false);
1560 final boolean validAttr = (version >= VERSION_FIX_PRIMARY)
1561 || (version >= VERSION_ADD_PRIMARY && !primaryPhysical);
1562 if (validAttr) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001563 mPrimaryStorageUuid = readStringAttribute(in,
1564 ATTR_PRIMARY_STORAGE_UUID);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001565 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001566 mForceAdoptable = readBooleanAttribute(in, ATTR_FORCE_ADOPTABLE, false);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001567
1568 } else if (TAG_VOLUME.equals(tag)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001569 final VolumeRecord rec = readVolumeRecord(in);
1570 mRecords.put(rec.fsUuid, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001571 }
1572 }
1573 }
1574 } catch (FileNotFoundException e) {
1575 // Missing metadata is okay, probably first boot
1576 } catch (IOException e) {
1577 Slog.wtf(TAG, "Failed reading metadata", e);
1578 } catch (XmlPullParserException e) {
1579 Slog.wtf(TAG, "Failed reading metadata", e);
1580 } finally {
1581 IoUtils.closeQuietly(fis);
1582 }
1583 }
1584
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001585 private void writeSettingsLocked() {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001586 FileOutputStream fos = null;
1587 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001588 fos = mSettingsFile.startWrite();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001589
1590 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001591 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001592 out.startDocument(null, true);
1593 out.startTag(null, TAG_VOLUMES);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001594 writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001595 writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001596 writeBooleanAttribute(out, ATTR_FORCE_ADOPTABLE, mForceAdoptable);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001597 final int size = mRecords.size();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001598 for (int i = 0; i < size; i++) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001599 final VolumeRecord rec = mRecords.valueAt(i);
1600 writeVolumeRecord(out, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001601 }
1602 out.endTag(null, TAG_VOLUMES);
1603 out.endDocument();
1604
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001605 mSettingsFile.finishWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001606 } catch (IOException e) {
1607 if (fos != null) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001608 mSettingsFile.failWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001609 }
1610 }
1611 }
1612
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001613 public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
1614 final int type = readIntAttribute(in, ATTR_TYPE);
1615 final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
1616 final VolumeRecord meta = new VolumeRecord(type, fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001617 meta.partGuid = readStringAttribute(in, ATTR_PART_GUID);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001618 meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
1619 meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001620 meta.createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
1621 meta.lastTrimMillis = readLongAttribute(in, ATTR_LAST_TRIM_MILLIS);
1622 meta.lastBenchMillis = readLongAttribute(in, ATTR_LAST_BENCH_MILLIS);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001623 return meta;
1624 }
1625
1626 public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
1627 out.startTag(null, TAG_VOLUME);
1628 writeIntAttribute(out, ATTR_TYPE, rec.type);
1629 writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001630 writeStringAttribute(out, ATTR_PART_GUID, rec.partGuid);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001631 writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
1632 writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001633 writeLongAttribute(out, ATTR_CREATED_MILLIS, rec.createdMillis);
1634 writeLongAttribute(out, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
1635 writeLongAttribute(out, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001636 out.endTag(null, TAG_VOLUME);
1637 }
1638
San Mehat207e5382010-02-04 20:46:54 -08001639 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001640 * Exposed API calls below here
1641 */
1642
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001643 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001644 public void registerListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001645 mCallbacks.register(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001646 }
1647
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001648 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001649 public void unregisterListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001650 mCallbacks.unregister(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001651 }
1652
Jeff Sharkey48877892015-03-18 11:27:19 -07001653 @Override
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -08001654 public void shutdown(final IMountShutdownObserver observer) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001655 enforcePermission(android.Manifest.permission.SHUTDOWN);
San Mehat4270e1e2010-01-29 05:32:19 -08001656
San Mehata5078592010-03-25 09:36:54 -07001657 Slog.i(TAG, "Shutting down");
Jeff Sharkey48877892015-03-18 11:27:19 -07001658 mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001659 }
1660
Jeff Sharkey48877892015-03-18 11:27:19 -07001661 @Override
San Mehatb1043402010-02-05 08:26:50 -08001662 public boolean isUsbMassStorageConnected() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001663 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001664 }
1665
Jeff Sharkey48877892015-03-18 11:27:19 -07001666 @Override
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -08001667 public void setUsbMassStorageEnabled(boolean enable) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001668 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001669 }
1670
Jeff Sharkey48877892015-03-18 11:27:19 -07001671 @Override
San Mehatb1043402010-02-05 08:26:50 -08001672 public boolean isUsbMassStorageEnabled() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001673 throw new UnsupportedOperationException();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001674 }
Jason parks9ed98bc2011-01-17 09:58:35 -06001675
Jeff Sharkey48877892015-03-18 11:27:19 -07001676 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001677 public String getVolumeState(String mountPoint) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001678 throw new UnsupportedOperationException();
San Mehat7fd0fee2009-12-17 07:12:23 -08001679 }
1680
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001681 @Override
Kenny Roote1ff2142010-10-12 11:20:01 -07001682 public boolean isExternalStorageEmulated() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001683 throw new UnsupportedOperationException();
Kenny Roote1ff2142010-10-12 11:20:01 -07001684 }
1685
Jeff Sharkey48877892015-03-18 11:27:19 -07001686 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001687 public int mountVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001688 mount(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001689 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 }
1691
Jeff Sharkey48877892015-03-18 11:27:19 -07001692 @Override
Ben Komalo13c71972011-09-07 16:35:56 -07001693 public void unmountVolume(String path, boolean force, boolean removeEncryption) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001694 unmount(findVolumeIdForPathOrThrow(path));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001695 }
1696
Jeff Sharkey48877892015-03-18 11:27:19 -07001697 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001698 public int formatVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001699 format(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001700 return 0;
1701 }
1702
1703 @Override
1704 public void mount(String volId) {
1705 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1706 waitForReady();
1707
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001708 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001709 if (isMountDisallowed(vol)) {
1710 throw new SecurityException("Mounting " + volId + " restricted by policy");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001711 }
1712 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001713 mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001714 } catch (NativeDaemonConnectorException e) {
1715 throw e.rethrowAsParcelableException();
1716 }
1717 }
1718
1719 @Override
1720 public void unmount(String volId) {
1721 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1722 waitForReady();
1723
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001724 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001725
1726 // TODO: expand PMS to know about multiple volumes
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001727 if (vol.isPrimaryPhysical()) {
1728 final long ident = Binder.clearCallingIdentity();
1729 try {
1730 synchronized (mUnmountLock) {
1731 mUnmountSignal = new CountDownLatch(1);
1732 mPms.updateExternalMediaStatus(false, true);
1733 waitForLatch(mUnmountSignal, "mUnmountSignal");
1734 mUnmountSignal = null;
1735 }
1736 } finally {
1737 Binder.restoreCallingIdentity(ident);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001738 }
1739 }
1740
1741 try {
1742 mConnector.execute("volume", "unmount", vol.id);
1743 } catch (NativeDaemonConnectorException e) {
1744 throw e.rethrowAsParcelableException();
1745 }
1746 }
1747
1748 @Override
1749 public void format(String volId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001750 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -08001751 waitForReady();
San Mehat5b77dab2010-01-26 13:28:50 -08001752
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001753 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001754 try {
Jeff Sharkey4e83cc92015-05-27 14:38:39 -07001755 mConnector.execute("volume", "format", vol.id, "auto");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001756 } catch (NativeDaemonConnectorException e) {
1757 throw e.rethrowAsParcelableException();
Jeff Sharkey48877892015-03-18 11:27:19 -07001758 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001759 }
1760
1761 @Override
Jeff Sharkey9756d752015-05-14 21:07:42 -07001762 public long benchmark(String volId) {
1763 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1764 waitForReady();
1765
1766 try {
Jeff Sharkey14cbe522015-07-08 14:06:37 -07001767 // TODO: make benchmark async so we don't block other commands
1768 final NativeDaemonEvent res = mConnector.execute(3 * DateUtils.MINUTE_IN_MILLIS,
1769 "volume", "benchmark", volId);
Jeff Sharkey9756d752015-05-14 21:07:42 -07001770 return Long.parseLong(res.getMessage());
Todd Kennedy8101ee62015-06-23 13:35:28 -07001771 } catch (NativeDaemonTimeoutException e) {
1772 return Long.MAX_VALUE;
Jeff Sharkey9756d752015-05-14 21:07:42 -07001773 } catch (NativeDaemonConnectorException e) {
1774 throw e.rethrowAsParcelableException();
1775 }
1776 }
1777
1778 @Override
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001779 public void partitionPublic(String diskId) {
1780 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1781 waitForReady();
1782
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001783 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001784 try {
1785 mConnector.execute("volume", "partition", diskId, "public");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001786 waitForLatch(latch, "partitionPublic", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001787 } catch (NativeDaemonConnectorException e) {
1788 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001789 } catch (TimeoutException e) {
1790 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001791 }
1792 }
1793
1794 @Override
1795 public void partitionPrivate(String diskId) {
1796 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001797 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001798 waitForReady();
1799
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001800 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001801 try {
1802 mConnector.execute("volume", "partition", diskId, "private");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001803 waitForLatch(latch, "partitionPrivate", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001804 } catch (NativeDaemonConnectorException e) {
1805 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001806 } catch (TimeoutException e) {
1807 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001808 }
1809 }
1810
1811 @Override
1812 public void partitionMixed(String diskId, int ratio) {
1813 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001814 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001815 waitForReady();
1816
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001817 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001818 try {
1819 mConnector.execute("volume", "partition", diskId, "mixed", ratio);
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001820 waitForLatch(latch, "partitionMixed", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001821 } catch (NativeDaemonConnectorException e) {
1822 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001823 } catch (TimeoutException e) {
1824 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001825 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 }
1827
Jeff Sharkey48877892015-03-18 11:27:19 -07001828 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001829 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001830 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1831 waitForReady();
1832
Jeff Sharkey50a05452015-04-29 11:24:52 -07001833 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001834 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001835 final VolumeRecord rec = mRecords.get(fsUuid);
1836 rec.nickname = nickname;
Jeff Sharkey50a05452015-04-29 11:24:52 -07001837 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001838 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001839 }
1840 }
1841
1842 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001843 public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001844 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1845 waitForReady();
1846
Jeff Sharkey50a05452015-04-29 11:24:52 -07001847 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001848 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001849 final VolumeRecord rec = mRecords.get(fsUuid);
1850 rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001851 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001852 writeSettingsLocked();
1853 }
1854 }
1855
1856 @Override
1857 public void forgetVolume(String fsUuid) {
1858 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1859 waitForReady();
1860
Jeff Sharkey50a05452015-04-29 11:24:52 -07001861 Preconditions.checkNotNull(fsUuid);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001862
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001863 synchronized (mLock) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001864 final VolumeRecord rec = mRecords.remove(fsUuid);
1865 if (rec != null && !TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001866 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001867 }
1868 mCallbacks.notifyVolumeForgotten(fsUuid);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001869
1870 // If this had been primary storage, revert back to internal and
1871 // reset vold so we bind into new volume into place.
1872 if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001873 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001874 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001875 }
1876
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001877 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001878 }
1879 }
1880
Jeff Sharkey7d2af542015-05-12 15:27:15 -07001881 @Override
1882 public void forgetAllVolumes() {
1883 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1884 waitForReady();
1885
Jeff Sharkey50a05452015-04-29 11:24:52 -07001886 synchronized (mLock) {
1887 for (int i = 0; i < mRecords.size(); i++) {
1888 final String fsUuid = mRecords.keyAt(i);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001889 final VolumeRecord rec = mRecords.valueAt(i);
1890 if (!TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001891 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001892 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001893 mCallbacks.notifyVolumeForgotten(fsUuid);
1894 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001895 mRecords.clear();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001896
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001897 if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)) {
1898 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
1899 }
1900
1901 writeSettingsLocked();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001902 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001903 }
1904 }
1905
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001906 private void forgetPartition(String partGuid) {
1907 try {
1908 mConnector.execute("volume", "forget_partition", partGuid);
1909 } catch (NativeDaemonConnectorException e) {
1910 Slog.w(TAG, "Failed to forget key for " + partGuid + ": " + e);
1911 }
1912 }
1913
Svet Ganov6ee871e2015-07-10 14:29:33 -07001914 private void remountUidExternalStorage(int uid, int mode) {
Jeff Sharkey9527b222015-06-24 15:24:48 -07001915 waitForReady();
1916
Svet Ganov6ee871e2015-07-10 14:29:33 -07001917 String modeName = "none";
1918 switch (mode) {
1919 case Zygote.MOUNT_EXTERNAL_DEFAULT: {
1920 modeName = "default";
1921 } break;
1922
1923 case Zygote.MOUNT_EXTERNAL_READ: {
1924 modeName = "read";
1925 } break;
1926
1927 case Zygote.MOUNT_EXTERNAL_WRITE: {
1928 modeName = "write";
1929 } break;
Jeff Sharkey9527b222015-06-24 15:24:48 -07001930 }
1931
1932 try {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001933 mConnector.execute("volume", "remount_uid", uid, modeName);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001934 } catch (NativeDaemonConnectorException e) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001935 Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001936 }
1937 }
1938
1939 @Override
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001940 public void setDebugFlags(int flags, int mask) {
1941 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1942 waitForReady();
1943
Jeff Sharkeyba512352015-11-12 20:17:45 -08001944 if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
Paul Lawrence20be5d62016-02-26 13:51:17 -08001945 if (StorageManager.isFileEncryptedNativeOnly()) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001946 throw new IllegalStateException(
1947 "Emulation not available on device with native FBE");
1948 }
Jeff Sharkey5a785162016-03-21 13:02:06 -06001949 if (mLockPatternUtils.isCredentialRequiredToDecrypt(false)) {
1950 throw new IllegalStateException(
1951 "Emulation requires disabling 'Secure start-up' in Settings > Security");
1952 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001953
Jeff Sharkey1176e512016-02-29 17:01:26 -07001954 final long token = Binder.clearCallingIdentity();
1955 try {
1956 final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
1957 SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001958
Jeff Sharkey1176e512016-02-29 17:01:26 -07001959 // Perform hard reboot to kick policy into place
1960 mContext.getSystemService(PowerManager.class).reboot(null);
1961 } finally {
1962 Binder.restoreCallingIdentity(token);
1963 }
Jeff Sharkeyba512352015-11-12 20:17:45 -08001964 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001965
Jeff Sharkeyba512352015-11-12 20:17:45 -08001966 if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
1967 synchronized (mLock) {
1968 mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
1969
1970 writeSettingsLocked();
1971 mHandler.obtainMessage(H_RESET).sendToTarget();
1972 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001973 }
1974 }
1975
1976 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001977 public String getPrimaryStorageUuid() {
1978 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1979 waitForReady();
1980
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001981 synchronized (mLock) {
1982 return mPrimaryStorageUuid;
1983 }
1984 }
1985
1986 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001987 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
1988 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1989 waitForReady();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001990
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001991 synchronized (mLock) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001992 if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) {
1993 throw new IllegalArgumentException("Primary storage already at " + volumeUuid);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001994 }
1995
1996 if (mMoveCallback != null) {
1997 throw new IllegalStateException("Move already in progress");
1998 }
1999 mMoveCallback = callback;
2000 mMoveTargetUuid = volumeUuid;
2001
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002002 // When moving to/from primary physical volume, we probably just nuked
2003 // the current storage location, so we have nothing to move.
2004 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
2005 || Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
2006 Slog.d(TAG, "Skipping move to/from primary physical");
2007 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
2008 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08002009 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002010
2011 } else {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07002012 final VolumeInfo from = findStorageForUuid(mPrimaryStorageUuid);
2013 final VolumeInfo to = findStorageForUuid(volumeUuid);
2014
2015 if (from == null) {
2016 Slog.w(TAG, "Failing move due to missing from volume " + mPrimaryStorageUuid);
2017 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2018 return;
2019 } else if (to == null) {
2020 Slog.w(TAG, "Failing move due to missing to volume " + volumeUuid);
2021 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2022 return;
2023 }
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002024
2025 try {
2026 mConnector.execute("volume", "move_storage", from.id, to.id);
2027 } catch (NativeDaemonConnectorException e) {
2028 throw e.rethrowAsParcelableException();
2029 }
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002030 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002031 }
2032 }
2033
2034 @Override
Mike Lockwoodecedfdc2011-06-08 15:11:59 -07002035 public int[] getStorageUsers(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002036 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehatc1b4ce92010-02-16 17:13:03 -08002037 waitForReady();
2038 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002039 final String[] r = NativeDaemonEvent.filterMessageList(
2040 mConnector.executeForList("storage", "users", path),
2041 VoldResponseCode.StorageUsersListResult);
2042
San Mehatc1b4ce92010-02-16 17:13:03 -08002043 // FMT: <pid> <process name>
2044 int[] data = new int[r.length];
2045 for (int i = 0; i < r.length; i++) {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002046 String[] tok = r[i].split(" ");
San Mehatc1b4ce92010-02-16 17:13:03 -08002047 try {
2048 data[i] = Integer.parseInt(tok[0]);
2049 } catch (NumberFormatException nfe) {
San Mehata5078592010-03-25 09:36:54 -07002050 Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
San Mehatc1b4ce92010-02-16 17:13:03 -08002051 return new int[0];
2052 }
2053 }
2054 return data;
2055 } catch (NativeDaemonConnectorException e) {
San Mehata5078592010-03-25 09:36:54 -07002056 Slog.e(TAG, "Failed to retrieve storage users list", e);
San Mehatc1b4ce92010-02-16 17:13:03 -08002057 return new int[0];
2058 }
2059 }
2060
San Mehatb1043402010-02-05 08:26:50 -08002061 private void warnOnNotMounted() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002062 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002063 for (int i = 0; i < mVolumes.size(); i++) {
2064 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07002065 if (vol.isPrimary() && vol.isMountedWritable()) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002066 // Cool beans, we have a mounted primary volume
2067 return;
2068 }
Jeff Sharkey32ee8312012-09-30 13:21:31 -07002069 }
San Mehatb1043402010-02-05 08:26:50 -08002070 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002071
2072 Slog.w(TAG, "No primary storage mounted!");
San Mehatb1043402010-02-05 08:26:50 -08002073 }
2074
San Mehat4270e1e2010-01-29 05:32:19 -08002075 public String[] getSecureContainerList() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002076 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002077 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002078 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002079
San Mehat4270e1e2010-01-29 05:32:19 -08002080 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002081 return NativeDaemonEvent.filterMessageList(
2082 mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
San Mehat4270e1e2010-01-29 05:32:19 -08002083 } catch (NativeDaemonConnectorException e) {
2084 return new String[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002085 }
2086 }
San Mehat36972292010-01-06 11:06:32 -08002087
Kenny Root6dceb882012-04-12 14:23:49 -07002088 public int createSecureContainer(String id, int sizeMb, String fstype, String key,
2089 int ownerUid, boolean external) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002090 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehat207e5382010-02-04 20:46:54 -08002091 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002092 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002093
San Mehatb1043402010-02-05 08:26:50 -08002094 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002095 try {
Jeff Sharkey56cd6462013-06-07 15:09:15 -07002096 mConnector.execute("asec", "create", id, sizeMb, fstype, new SensitiveArg(key),
2097 ownerUid, external ? "1" : "0");
San Mehat4270e1e2010-01-29 05:32:19 -08002098 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002099 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002100 }
San Mehata181b212010-02-11 06:50:20 -08002101
2102 if (rc == StorageResultCode.OperationSucceeded) {
2103 synchronized (mAsecMountSet) {
2104 mAsecMountSet.add(id);
2105 }
2106 }
San Mehat4270e1e2010-01-29 05:32:19 -08002107 return rc;
San Mehat36972292010-01-06 11:06:32 -08002108 }
2109
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002110 @Override
2111 public int resizeSecureContainer(String id, int sizeMb, String key) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002112 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002113 waitForReady();
2114 warnOnNotMounted();
2115
2116 int rc = StorageResultCode.OperationSucceeded;
2117 try {
2118 mConnector.execute("asec", "resize", id, sizeMb, new SensitiveArg(key));
2119 } catch (NativeDaemonConnectorException e) {
2120 rc = StorageResultCode.OperationFailedInternalError;
2121 }
2122 return rc;
2123 }
2124
San Mehat4270e1e2010-01-29 05:32:19 -08002125 public int finalizeSecureContainer(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002126 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehatb1043402010-02-05 08:26:50 -08002127 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002128
San Mehatb1043402010-02-05 08:26:50 -08002129 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002130 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002131 mConnector.execute("asec", "finalize", id);
San Mehata181b212010-02-11 06:50:20 -08002132 /*
2133 * Finalization does a remount, so no need
2134 * to update mAsecMountSet
2135 */
San Mehat4270e1e2010-01-29 05:32:19 -08002136 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002137 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002138 }
San Mehat4270e1e2010-01-29 05:32:19 -08002139 return rc;
San Mehat36972292010-01-06 11:06:32 -08002140 }
2141
Kenny Root6dceb882012-04-12 14:23:49 -07002142 public int fixPermissionsSecureContainer(String id, int gid, String filename) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002143 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Kenny Root6dceb882012-04-12 14:23:49 -07002144 warnOnNotMounted();
2145
2146 int rc = StorageResultCode.OperationSucceeded;
2147 try {
2148 mConnector.execute("asec", "fixperms", id, gid, filename);
2149 /*
2150 * Fix permissions does a remount, so no need to update
2151 * mAsecMountSet
2152 */
2153 } catch (NativeDaemonConnectorException e) {
2154 rc = StorageResultCode.OperationFailedInternalError;
2155 }
2156 return rc;
2157 }
2158
San Mehatd9709982010-02-18 11:43:03 -08002159 public int destroySecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002160 enforcePermission(android.Manifest.permission.ASEC_DESTROY);
San Mehat207e5382010-02-04 20:46:54 -08002161 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002162 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002163
Kenny Rootaa485402010-09-14 14:49:41 -07002164 /*
2165 * Force a GC to make sure AssetManagers in other threads of the
2166 * system_server are cleaned up. We have to do this since AssetManager
2167 * instances are kept as a WeakReference and it's possible we have files
2168 * open on the external storage.
2169 */
2170 Runtime.getRuntime().gc();
2171
San Mehatb1043402010-02-05 08:26:50 -08002172 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002173 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002174 final Command cmd = new Command("asec", "destroy", id);
2175 if (force) {
2176 cmd.appendArg("force");
2177 }
2178 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002179 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002180 int code = e.getCode();
2181 if (code == VoldResponseCode.OpFailedStorageBusy) {
2182 rc = StorageResultCode.OperationFailedStorageBusy;
2183 } else {
2184 rc = StorageResultCode.OperationFailedInternalError;
2185 }
San Mehat02735bc2010-01-26 15:18:08 -08002186 }
San Mehata181b212010-02-11 06:50:20 -08002187
2188 if (rc == StorageResultCode.OperationSucceeded) {
2189 synchronized (mAsecMountSet) {
2190 if (mAsecMountSet.contains(id)) {
2191 mAsecMountSet.remove(id);
2192 }
2193 }
2194 }
2195
San Mehat4270e1e2010-01-29 05:32:19 -08002196 return rc;
San Mehat36972292010-01-06 11:06:32 -08002197 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002198
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002199 public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002200 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002201 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002202 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002203
San Mehata181b212010-02-11 06:50:20 -08002204 synchronized (mAsecMountSet) {
2205 if (mAsecMountSet.contains(id)) {
2206 return StorageResultCode.OperationFailedStorageMounted;
2207 }
2208 }
2209
San Mehatb1043402010-02-05 08:26:50 -08002210 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002211 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002212 mConnector.execute("asec", "mount", id, new SensitiveArg(key), ownerUid,
2213 readOnly ? "ro" : "rw");
San Mehat4270e1e2010-01-29 05:32:19 -08002214 } catch (NativeDaemonConnectorException e) {
Kenny Rootf0304622010-03-19 19:20:42 -07002215 int code = e.getCode();
2216 if (code != VoldResponseCode.OpFailedStorageBusy) {
2217 rc = StorageResultCode.OperationFailedInternalError;
2218 }
San Mehat02735bc2010-01-26 15:18:08 -08002219 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002220
2221 if (rc == StorageResultCode.OperationSucceeded) {
2222 synchronized (mAsecMountSet) {
2223 mAsecMountSet.add(id);
2224 }
2225 }
San Mehat4270e1e2010-01-29 05:32:19 -08002226 return rc;
San Mehat36972292010-01-06 11:06:32 -08002227 }
2228
San Mehatd9709982010-02-18 11:43:03 -08002229 public int unmountSecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002230 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002231 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002232 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002233
San Mehat6cdd9c02010-02-09 14:45:20 -08002234 synchronized (mAsecMountSet) {
2235 if (!mAsecMountSet.contains(id)) {
San Mehata181b212010-02-11 06:50:20 -08002236 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehat6cdd9c02010-02-09 14:45:20 -08002237 }
2238 }
2239
Kenny Rootaa485402010-09-14 14:49:41 -07002240 /*
2241 * Force a GC to make sure AssetManagers in other threads of the
2242 * system_server are cleaned up. We have to do this since AssetManager
2243 * instances are kept as a WeakReference and it's possible we have files
2244 * open on the external storage.
2245 */
2246 Runtime.getRuntime().gc();
2247
San Mehatb1043402010-02-05 08:26:50 -08002248 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002249 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002250 final Command cmd = new Command("asec", "unmount", id);
2251 if (force) {
2252 cmd.appendArg("force");
2253 }
2254 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002255 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002256 int code = e.getCode();
2257 if (code == VoldResponseCode.OpFailedStorageBusy) {
2258 rc = StorageResultCode.OperationFailedStorageBusy;
2259 } else {
2260 rc = StorageResultCode.OperationFailedInternalError;
2261 }
San Mehat02735bc2010-01-26 15:18:08 -08002262 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002263
2264 if (rc == StorageResultCode.OperationSucceeded) {
2265 synchronized (mAsecMountSet) {
2266 mAsecMountSet.remove(id);
2267 }
2268 }
San Mehat4270e1e2010-01-29 05:32:19 -08002269 return rc;
San Mehat9dba7092010-01-18 06:47:41 -08002270 }
2271
San Mehat6cdd9c02010-02-09 14:45:20 -08002272 public boolean isSecureContainerMounted(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002273 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat6cdd9c02010-02-09 14:45:20 -08002274 waitForReady();
2275 warnOnNotMounted();
2276
2277 synchronized (mAsecMountSet) {
2278 return mAsecMountSet.contains(id);
2279 }
2280 }
2281
San Mehat4270e1e2010-01-29 05:32:19 -08002282 public int renameSecureContainer(String oldId, String newId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002283 enforcePermission(android.Manifest.permission.ASEC_RENAME);
San Mehat207e5382010-02-04 20:46:54 -08002284 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002285 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002286
San Mehata181b212010-02-11 06:50:20 -08002287 synchronized (mAsecMountSet) {
San Mehat85451ee2010-02-24 08:54:18 -08002288 /*
Jason parks9ed98bc2011-01-17 09:58:35 -06002289 * Because a mounted container has active internal state which cannot be
San Mehat85451ee2010-02-24 08:54:18 -08002290 * changed while active, we must ensure both ids are not currently mounted.
2291 */
2292 if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
San Mehata181b212010-02-11 06:50:20 -08002293 return StorageResultCode.OperationFailedStorageMounted;
2294 }
2295 }
2296
San Mehatb1043402010-02-05 08:26:50 -08002297 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002298 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002299 mConnector.execute("asec", "rename", oldId, newId);
San Mehat4270e1e2010-01-29 05:32:19 -08002300 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002301 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002302 }
San Mehata181b212010-02-11 06:50:20 -08002303
San Mehat4270e1e2010-01-29 05:32:19 -08002304 return rc;
San Mehat45f61042010-01-23 08:12:43 -08002305 }
2306
San Mehat4270e1e2010-01-29 05:32:19 -08002307 public String getSecureContainerPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002308 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002309 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002310 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002311
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002312 final NativeDaemonEvent event;
San Mehat2d66cef2010-03-23 11:12:52 -07002313 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002314 event = mConnector.execute("asec", "path", id);
2315 event.checkCode(VoldResponseCode.AsecPathResult);
2316 return event.getMessage();
San Mehat2d66cef2010-03-23 11:12:52 -07002317 } catch (NativeDaemonConnectorException e) {
2318 int code = e.getCode();
2319 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Fredrik Helmera20c8ef2011-02-09 16:16:10 +01002320 Slog.i(TAG, String.format("Container '%s' not found", id));
2321 return null;
San Mehat22dd86e2010-01-12 12:21:18 -08002322 } else {
San Mehat2d66cef2010-03-23 11:12:52 -07002323 throw new IllegalStateException(String.format("Unexpected response code %d", code));
San Mehat22dd86e2010-01-12 12:21:18 -08002324 }
2325 }
San Mehat22dd86e2010-01-12 12:21:18 -08002326 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002327
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002328 public String getSecureContainerFilesystemPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002329 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002330 waitForReady();
2331 warnOnNotMounted();
2332
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002333 final NativeDaemonEvent event;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002334 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002335 event = mConnector.execute("asec", "fspath", id);
2336 event.checkCode(VoldResponseCode.AsecPathResult);
2337 return event.getMessage();
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002338 } catch (NativeDaemonConnectorException e) {
2339 int code = e.getCode();
2340 if (code == VoldResponseCode.OpFailedStorageNotFound) {
2341 Slog.i(TAG, String.format("Container '%s' not found", id));
2342 return null;
2343 } else {
2344 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2345 }
2346 }
2347 }
2348
Jeff Sharkey48877892015-03-18 11:27:19 -07002349 @Override
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002350 public void finishMediaUpdate() {
Jeff Sharkey9527b222015-06-24 15:24:48 -07002351 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
Rubin Xucd7a0142015-04-17 23:45:27 +01002352 throw new SecurityException("no permission to call finishMediaUpdate()");
2353 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002354 if (mUnmountSignal != null) {
2355 mUnmountSignal.countDown();
2356 } else {
2357 Slog.w(TAG, "Odd, nobody asked to unmount?");
2358 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002359 }
Kenny Root02c87302010-07-01 08:10:18 -07002360
Kenny Roota02b8b02010-08-05 16:14:17 -07002361 private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
2362 if (callerUid == android.os.Process.SYSTEM_UID) {
2363 return true;
2364 }
2365
Kenny Root02c87302010-07-01 08:10:18 -07002366 if (packageName == null) {
2367 return false;
2368 }
2369
Jeff Sharkeycd654482016-01-08 17:42:11 -07002370 final int packageUid = mPms.getPackageUid(packageName,
2371 PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callerUid));
Kenny Root02c87302010-07-01 08:10:18 -07002372
2373 if (DEBUG_OBB) {
2374 Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
2375 packageUid + ", callerUid = " + callerUid);
2376 }
2377
2378 return callerUid == packageUid;
2379 }
2380
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002381 public String getMountedObbPath(String rawPath) {
2382 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002383
Kenny Root02c87302010-07-01 08:10:18 -07002384 waitForReady();
2385 warnOnNotMounted();
2386
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002387 final ObbState state;
Rubin Xucd7a0142015-04-17 23:45:27 +01002388 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002389 state = mObbPathToStateMap.get(rawPath);
2390 }
2391 if (state == null) {
2392 Slog.w(TAG, "Failed to find OBB mounted at " + rawPath);
2393 return null;
2394 }
2395
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002396 final NativeDaemonEvent event;
Kenny Root02c87302010-07-01 08:10:18 -07002397 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07002398 event = mConnector.execute("obb", "path", state.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002399 event.checkCode(VoldResponseCode.AsecPathResult);
2400 return event.getMessage();
Kenny Root02c87302010-07-01 08:10:18 -07002401 } catch (NativeDaemonConnectorException e) {
2402 int code = e.getCode();
2403 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Kenny Roota02b8b02010-08-05 16:14:17 -07002404 return null;
Kenny Root02c87302010-07-01 08:10:18 -07002405 } else {
2406 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2407 }
2408 }
2409 }
2410
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002411 @Override
2412 public boolean isObbMounted(String rawPath) {
2413 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002414 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002415 return mObbPathToStateMap.containsKey(rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002416 }
Kenny Root02c87302010-07-01 08:10:18 -07002417 }
2418
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002419 @Override
2420 public void mountObb(
2421 String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) {
2422 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2423 Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
2424 Preconditions.checkNotNull(token, "token cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002425
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002426 final int callingUid = Binder.getCallingUid();
2427 final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce);
2428 final ObbAction action = new MountObbAction(obbState, key, callingUid);
Kenny Roota02b8b02010-08-05 16:14:17 -07002429 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
2430
2431 if (DEBUG_OBB)
2432 Slog.i(TAG, "Send to OBB handler: " + action.toString());
Kenny Root02c87302010-07-01 08:10:18 -07002433 }
2434
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002435 @Override
2436 public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
2437 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2438
2439 final ObbState existingState;
Rubin Xucd7a0142015-04-17 23:45:27 +01002440 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002441 existingState = mObbPathToStateMap.get(rawPath);
Kenny Rootf1121dc2010-09-29 07:30:53 -07002442 }
2443
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002444 if (existingState != null) {
2445 // TODO: separate state object from request data
2446 final int callingUid = Binder.getCallingUid();
2447 final ObbState newState = new ObbState(
2448 rawPath, existingState.canonicalPath, callingUid, token, nonce);
2449 final ObbAction action = new UnmountObbAction(newState, force);
2450 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root02c87302010-07-01 08:10:18 -07002451
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002452 if (DEBUG_OBB)
2453 Slog.i(TAG, "Send to OBB handler: " + action.toString());
2454 } else {
2455 Slog.w(TAG, "Unknown OBB mount at " + rawPath);
2456 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002457 }
2458
Ben Komalo444eca22011-09-01 15:17:44 -07002459 @Override
2460 public int getEncryptionState() {
2461 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2462 "no permission to access the crypt keeper");
2463
2464 waitForReady();
2465
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002466 final NativeDaemonEvent event;
Ben Komalo444eca22011-09-01 15:17:44 -07002467 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002468 event = mCryptConnector.execute("cryptfs", "cryptocomplete");
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002469 return Integer.parseInt(event.getMessage());
Ben Komalo444eca22011-09-01 15:17:44 -07002470 } catch (NumberFormatException e) {
2471 // Bad result - unexpected.
2472 Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
2473 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2474 } catch (NativeDaemonConnectorException e) {
2475 // Something bad happened.
2476 Slog.w(TAG, "Error in communicating with cryptfs in validating");
2477 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2478 }
2479 }
2480
2481 @Override
Jason parks5af0b912010-11-29 09:05:25 -06002482 public int decryptStorage(String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002483 if (TextUtils.isEmpty(password)) {
2484 throw new IllegalArgumentException("password cannot be empty");
Jason parks5af0b912010-11-29 09:05:25 -06002485 }
2486
Jason parks8888c592011-01-20 22:46:41 -06002487 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2488 "no permission to access the crypt keeper");
Jason parks5af0b912010-11-29 09:05:25 -06002489
2490 waitForReady();
2491
2492 if (DEBUG_EVENTS) {
2493 Slog.i(TAG, "decrypting storage...");
2494 }
2495
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002496 final NativeDaemonEvent event;
Jason parks5af0b912010-11-29 09:05:25 -06002497 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002498 event = mCryptConnector.execute("cryptfs", "checkpw", new SensitiveArg(password));
Jason parks9ed98bc2011-01-17 09:58:35 -06002499
Fredrik Roubertda6aedf2011-12-20 17:34:43 +01002500 final int code = Integer.parseInt(event.getMessage());
Jason parks9ed98bc2011-01-17 09:58:35 -06002501 if (code == 0) {
2502 // Decrypt was successful. Post a delayed message before restarting in order
2503 // to let the UI to clear itself
2504 mHandler.postDelayed(new Runnable() {
2505 public void run() {
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002506 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002507 mCryptConnector.execute("cryptfs", "restart");
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002508 } catch (NativeDaemonConnectorException e) {
2509 Slog.e(TAG, "problem executing in background", e);
2510 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002511 }
Jason parksf7b3cd42011-01-27 09:28:25 -06002512 }, 1000); // 1 second
Jason parks9ed98bc2011-01-17 09:58:35 -06002513 }
2514
2515 return code;
Jason parks5af0b912010-11-29 09:05:25 -06002516 } catch (NativeDaemonConnectorException e) {
2517 // Decryption failed
2518 return e.getCode();
2519 }
Jason parks5af0b912010-11-29 09:05:25 -06002520 }
2521
Paul Lawrence46791e72014-04-03 09:10:26 -07002522 public int encryptStorage(int type, String password) {
2523 if (TextUtils.isEmpty(password) && type != StorageManager.CRYPT_TYPE_DEFAULT) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002524 throw new IllegalArgumentException("password cannot be empty");
Jason parks56aa5322011-01-07 09:01:15 -06002525 }
2526
Jason parks8888c592011-01-20 22:46:41 -06002527 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2528 "no permission to access the crypt keeper");
Jason parks56aa5322011-01-07 09:01:15 -06002529
2530 waitForReady();
2531
2532 if (DEBUG_EVENTS) {
Jason parks8888c592011-01-20 22:46:41 -06002533 Slog.i(TAG, "encrypting storage...");
Jason parks56aa5322011-01-07 09:01:15 -06002534 }
2535
2536 try {
Paul Lawrence5096d9e2015-09-09 13:05:45 -07002537 if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
2538 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2539 CRYPTO_TYPES[type]);
2540 } else {
2541 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2542 CRYPTO_TYPES[type], new SensitiveArg(password));
2543 }
Jason parks56aa5322011-01-07 09:01:15 -06002544 } catch (NativeDaemonConnectorException e) {
2545 // Encryption failed
2546 return e.getCode();
2547 }
2548
2549 return 0;
2550 }
2551
Paul Lawrence8e397362014-01-27 15:22:30 -08002552 /** Set the password for encrypting the master key.
2553 * @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
2554 * @param password The password to set.
2555 */
2556 public int changeEncryptionPassword(int type, String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002557 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2558 "no permission to access the crypt keeper");
2559
2560 waitForReady();
2561
2562 if (DEBUG_EVENTS) {
2563 Slog.i(TAG, "changing encryption password...");
2564 }
2565
2566 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002567 NativeDaemonEvent event = mCryptConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type],
Paul Lawrence05487612015-06-09 13:35:38 -07002568 new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002569 return Integer.parseInt(event.getMessage());
Jason parksf7b3cd42011-01-27 09:28:25 -06002570 } catch (NativeDaemonConnectorException e) {
2571 // Encryption failed
2572 return e.getCode();
2573 }
2574 }
2575
Christopher Tate32418be2011-10-10 13:51:12 -07002576 /**
2577 * Validate a user-supplied password string with cryptfs
2578 */
2579 @Override
2580 public int verifyEncryptionPassword(String password) throws RemoteException {
2581 // Only the system process is permitted to validate passwords
2582 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2583 throw new SecurityException("no permission to access the crypt keeper");
2584 }
2585
2586 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2587 "no permission to access the crypt keeper");
2588
2589 if (TextUtils.isEmpty(password)) {
2590 throw new IllegalArgumentException("password cannot be empty");
2591 }
2592
2593 waitForReady();
2594
2595 if (DEBUG_EVENTS) {
2596 Slog.i(TAG, "validating encryption password...");
2597 }
2598
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002599 final NativeDaemonEvent event;
Christopher Tate32418be2011-10-10 13:51:12 -07002600 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002601 event = mCryptConnector.execute("cryptfs", "verifypw", new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002602 Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
2603 return Integer.parseInt(event.getMessage());
Christopher Tate32418be2011-10-10 13:51:12 -07002604 } catch (NativeDaemonConnectorException e) {
2605 // Encryption failed
2606 return e.getCode();
2607 }
2608 }
2609
Paul Lawrence8e397362014-01-27 15:22:30 -08002610 /**
2611 * Get the type of encryption used to encrypt the master key.
2612 * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
2613 */
2614 @Override
Svetoslav16e4a1a2014-09-29 18:16:20 -07002615 public int getPasswordType() {
Paul Lawrence8e397362014-01-27 15:22:30 -08002616
2617 waitForReady();
2618
2619 final NativeDaemonEvent event;
2620 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002621 event = mCryptConnector.execute("cryptfs", "getpwtype");
Paul Lawrence8e397362014-01-27 15:22:30 -08002622 for (int i = 0; i < CRYPTO_TYPES.length; ++i) {
2623 if (CRYPTO_TYPES[i].equals(event.getMessage()))
2624 return i;
2625 }
2626
2627 throw new IllegalStateException("unexpected return from cryptfs");
2628 } catch (NativeDaemonConnectorException e) {
2629 throw e.rethrowAsParcelableException();
2630 }
2631 }
2632
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002633 /**
2634 * Set a field in the crypto header.
2635 * @param field field to set
2636 * @param contents contents to set in field
2637 */
2638 @Override
2639 public void setField(String field, String contents) throws RemoteException {
2640
2641 waitForReady();
2642
2643 final NativeDaemonEvent event;
2644 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002645 event = mCryptConnector.execute("cryptfs", "setfield", field, contents);
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002646 } catch (NativeDaemonConnectorException e) {
2647 throw e.rethrowAsParcelableException();
2648 }
2649 }
2650
2651 /**
2652 * Gets a field from the crypto header.
2653 * @param field field to get
2654 * @return contents of field
2655 */
2656 @Override
2657 public String getField(String field) throws RemoteException {
2658
2659 waitForReady();
2660
2661 final NativeDaemonEvent event;
2662 try {
2663 final String[] contents = NativeDaemonEvent.filterMessageList(
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002664 mCryptConnector.executeForList("cryptfs", "getfield", field),
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002665 VoldResponseCode.CryptfsGetfieldResult);
2666 String result = new String();
2667 for (String content : contents) {
2668 result += content;
2669 }
2670 return result;
2671 } catch (NativeDaemonConnectorException e) {
2672 throw e.rethrowAsParcelableException();
2673 }
2674 }
2675
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002676 /**
2677 * Is userdata convertible to file based encryption?
2678 * @return non zero for convertible
2679 */
2680 @Override
2681 public boolean isConvertibleToFBE() throws RemoteException {
2682
2683 waitForReady();
2684
2685 final NativeDaemonEvent event;
2686 try {
2687 event = mCryptConnector.execute("cryptfs", "isConvertibleToFBE");
2688 return Integer.parseInt(event.getMessage()) != 0;
2689 } catch (NativeDaemonConnectorException e) {
2690 throw e.rethrowAsParcelableException();
2691 }
2692 }
2693
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002694 @Override
Paul Lawrence945490c2014-03-27 16:37:28 +00002695 public String getPassword() throws RemoteException {
Rubin Xucd7a0142015-04-17 23:45:27 +01002696 mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE,
2697 "only keyguard can retrieve password");
Paul Lawrence945490c2014-03-27 16:37:28 +00002698 if (!isReady()) {
2699 return new String();
2700 }
2701
2702 final NativeDaemonEvent event;
2703 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002704 event = mCryptConnector.execute("cryptfs", "getpw");
Paul Lawrence24063b52015-01-06 13:11:23 -08002705 if ("-1".equals(event.getMessage())) {
2706 // -1 equals no password
2707 return null;
2708 }
Paul Lawrence05487612015-06-09 13:35:38 -07002709 return event.getMessage();
Paul Lawrence945490c2014-03-27 16:37:28 +00002710 } catch (NativeDaemonConnectorException e) {
2711 throw e.rethrowAsParcelableException();
Paul Lawrence24063b52015-01-06 13:11:23 -08002712 } catch (IllegalArgumentException e) {
2713 Slog.e(TAG, "Invalid response to getPassword");
2714 return null;
Paul Lawrence945490c2014-03-27 16:37:28 +00002715 }
2716 }
2717
2718 @Override
2719 public void clearPassword() throws RemoteException {
2720 if (!isReady()) {
2721 return;
2722 }
2723
2724 final NativeDaemonEvent event;
2725 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002726 event = mCryptConnector.execute("cryptfs", "clearpw");
Paul Lawrence945490c2014-03-27 16:37:28 +00002727 } catch (NativeDaemonConnectorException e) {
2728 throw e.rethrowAsParcelableException();
2729 }
2730 }
2731
2732 @Override
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002733 public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002734 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002735 waitForReady();
2736
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002737 try {
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002738 mCryptConnector.execute("cryptfs", "create_user_key", userId, serialNumber,
2739 ephemeral ? 1 : 0);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002740 } catch (NativeDaemonConnectorException e) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002741 throw e.rethrowAsParcelableException();
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002742 }
2743 }
2744
Paul Crowley7ec733f2015-05-19 12:42:00 +01002745 @Override
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002746 public void destroyUserKey(int userId) {
2747 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowley7ec733f2015-05-19 12:42:00 +01002748 waitForReady();
2749
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002750 try {
2751 mCryptConnector.execute("cryptfs", "destroy_user_key", userId);
2752 } catch (NativeDaemonConnectorException e) {
2753 throw e.rethrowAsParcelableException();
2754 }
2755 }
2756
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002757 private SensitiveArg encodeBytes(byte[] bytes) {
2758 if (ArrayUtils.isEmpty(bytes)) {
2759 return new SensitiveArg("!");
2760 } else {
2761 return new SensitiveArg(HexDump.toHexString(bytes));
2762 }
2763 }
2764
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002765 @Override
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002766 public void changeUserKey(int userId, int serialNumber,
2767 byte[] token, byte[] oldSecret, byte[] newSecret) {
2768 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2769 waitForReady();
2770
2771 try {
2772 mCryptConnector.execute("cryptfs", "change_user_key", userId, serialNumber,
2773 encodeBytes(token), encodeBytes(oldSecret), encodeBytes(newSecret));
2774 } catch (NativeDaemonConnectorException e) {
2775 throw e.rethrowAsParcelableException();
2776 }
2777 }
2778
2779 @Override
2780 public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002781 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2782 waitForReady();
2783
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07002784 // When a user has secure lock screen, require a challenge token to
2785 // actually unlock. This check is mostly in place for emulation mode.
2786 if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(token)) {
2787 throw new IllegalStateException("Token required to unlock secure user " + userId);
2788 }
2789
Paul Crowley7ec733f2015-05-19 12:42:00 +01002790 try {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002791 mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber,
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002792 encodeBytes(token), encodeBytes(secret));
Paul Crowley7ec733f2015-05-19 12:42:00 +01002793 } catch (NativeDaemonConnectorException e) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002794 throw e.rethrowAsParcelableException();
2795 }
2796
2797 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002798 mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002799 }
2800 }
2801
2802 @Override
2803 public void lockUserKey(int userId) {
2804 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2805 waitForReady();
2806
2807 try {
2808 mCryptConnector.execute("cryptfs", "lock_user_key", userId);
2809 } catch (NativeDaemonConnectorException e) {
2810 throw e.rethrowAsParcelableException();
2811 }
2812
2813 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002814 mLocalUnlockedUsers = ArrayUtils.removeInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002815 }
2816 }
2817
2818 @Override
2819 public boolean isUserKeyUnlocked(int userId) {
Paul Lawrence20be5d62016-02-26 13:51:17 -08002820 if (StorageManager.isFileEncryptedNativeOrEmulated()) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002821 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002822 return ArrayUtils.contains(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002823 }
2824 } else {
2825 return true;
2826 }
2827 }
2828
2829 @Override
Jeff Sharkey47f71082016-02-01 17:03:54 -07002830 public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002831 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2832 waitForReady();
2833
2834 try {
2835 mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid),
Jeff Sharkey47f71082016-02-01 17:03:54 -07002836 userId, serialNumber, flags);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002837 } catch (NativeDaemonConnectorException e) {
2838 throw e.rethrowAsParcelableException();
Paul Crowley7ec733f2015-05-19 12:42:00 +01002839 }
2840 }
2841
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002842 @Override
Daichi Hirono91e3b502015-12-16 09:24:16 +09002843 public ParcelFileDescriptor mountAppFuse(final String name) throws RemoteException {
Daichi Hironobee50c02015-12-14 11:00:54 +09002844 try {
Daichi Hirono91e3b502015-12-16 09:24:16 +09002845 final int uid = Binder.getCallingUid();
Daichi Hironofd7d57e2016-01-29 14:30:58 +09002846 final int pid = Binder.getCallingPid();
Daichi Hironobee50c02015-12-14 11:00:54 +09002847 final NativeDaemonEvent event =
Daichi Hironofd7d57e2016-01-29 14:30:58 +09002848 mConnector.execute("appfuse", "mount", uid, pid, name);
Daichi Hironobee50c02015-12-14 11:00:54 +09002849 if (event.getFileDescriptors() == null) {
Daichi Hirono91e3b502015-12-16 09:24:16 +09002850 throw new RemoteException("AppFuse FD from vold is null.");
Daichi Hironobee50c02015-12-14 11:00:54 +09002851 }
Daichi Hirono91e3b502015-12-16 09:24:16 +09002852 return ParcelFileDescriptor.fromFd(
2853 event.getFileDescriptors()[0],
2854 mHandler,
2855 new ParcelFileDescriptor.OnCloseListener() {
2856 @Override
2857 public void onClose(IOException e) {
2858 try {
2859 final NativeDaemonEvent event = mConnector.execute(
Daichi Hironofd7d57e2016-01-29 14:30:58 +09002860 "appfuse", "unmount", uid, pid, name);
Daichi Hirono91e3b502015-12-16 09:24:16 +09002861 } catch (NativeDaemonConnectorException unmountException) {
2862 Log.e(TAG, "Failed to unmount appfuse.");
2863 }
2864 }
2865 });
Daichi Hironobee50c02015-12-14 11:00:54 +09002866 } catch (NativeDaemonConnectorException e) {
2867 throw e.rethrowAsParcelableException();
Daichi Hirono91e3b502015-12-16 09:24:16 +09002868 } catch (IOException e) {
2869 throw new RemoteException(e.getMessage());
Daichi Hironobee50c02015-12-14 11:00:54 +09002870 }
Daichi Hirono9e8d9e22015-11-13 14:37:00 +09002871 }
2872
2873 @Override
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002874 public int mkdirs(String callingPkg, String appPath) {
2875 final int userId = UserHandle.getUserId(Binder.getCallingUid());
2876 final UserEnvironment userEnv = new UserEnvironment(userId);
2877
2878 // Validate that reported package name belongs to caller
2879 final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
2880 Context.APP_OPS_SERVICE);
2881 appOps.checkPackage(Binder.getCallingUid(), callingPkg);
2882
Jeff Sharkey48877892015-03-18 11:27:19 -07002883 File appFile = null;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002884 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07002885 appFile = new File(appPath).getCanonicalFile();
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002886 } catch (IOException e) {
2887 Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
2888 return -1;
2889 }
2890
2891 // Try translating the app path into a vold path, but require that it
2892 // belong to the calling package.
Jeff Sharkey48877892015-03-18 11:27:19 -07002893 if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) ||
2894 FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) ||
2895 FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) {
2896 appPath = appFile.getAbsolutePath();
2897 if (!appPath.endsWith("/")) {
2898 appPath = appPath + "/";
2899 }
2900
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002901 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07002902 mConnector.execute("volume", "mkdirs", appPath);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002903 return 0;
2904 } catch (NativeDaemonConnectorException e) {
2905 return e.getCode();
2906 }
2907 }
2908
Jeff Sharkey48877892015-03-18 11:27:19 -07002909 throw new SecurityException("Invalid mkdirs path: " + appFile);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002910 }
2911
2912 @Override
Jeff Sharkey46349872015-07-28 10:49:47 -07002913 public StorageVolume[] getVolumeList(int uid, String packageName, int flags) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002914 final int userId = UserHandle.getUserId(uid);
Jeff Sharkey46349872015-07-28 10:49:47 -07002915 final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0;
2916
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002917 boolean reportUnmounted = false;
Jeff Sharkey48877892015-03-18 11:27:19 -07002918 boolean foundPrimary = false;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002919
Svetoslav38c3dbb2015-07-14 11:27:06 -07002920 final long identity = Binder.clearCallingIdentity();
2921 try {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002922 if (!mMountServiceInternal.hasExternalStorage(uid, packageName)) {
2923 reportUnmounted = true;
2924 }
2925 if (!isUserKeyUnlocked(userId)) {
2926 reportUnmounted = true;
2927 }
Svetoslav38c3dbb2015-07-14 11:27:06 -07002928 } finally {
2929 Binder.restoreCallingIdentity(identity);
2930 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07002931
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002932 final ArrayList<StorageVolume> res = new ArrayList<>();
Jeff Sharkey48877892015-03-18 11:27:19 -07002933 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002934 for (int i = 0; i < mVolumes.size(); i++) {
2935 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey46349872015-07-28 10:49:47 -07002936 if (forWrite ? vol.isVisibleForWrite(userId) : vol.isVisibleForRead(userId)) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07002937 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
2938 reportUnmounted);
Jeff Sharkey48877892015-03-18 11:27:19 -07002939 if (vol.isPrimary()) {
2940 res.add(0, userVol);
2941 foundPrimary = true;
2942 } else {
2943 res.add(userVol);
2944 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002945 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002946 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002947 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002948
2949 if (!foundPrimary) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002950 Log.w(TAG, "No primary storage defined yet; hacking together a stub");
Jeff Sharkey48877892015-03-18 11:27:19 -07002951
2952 final boolean primaryPhysical = SystemProperties.getBoolean(
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002953 StorageManager.PROP_PRIMARY_PHYSICAL, false);
Jeff Sharkey48877892015-03-18 11:27:19 -07002954
2955 final String id = "stub_primary";
2956 final File path = Environment.getLegacyExternalStorageDirectory();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002957 final String description = mContext.getString(android.R.string.unknownName);
Jeff Sharkey48877892015-03-18 11:27:19 -07002958 final boolean primary = true;
2959 final boolean removable = primaryPhysical;
2960 final boolean emulated = !primaryPhysical;
2961 final long mtpReserveSize = 0L;
2962 final boolean allowMassStorage = false;
2963 final long maxFileSize = 0L;
2964 final UserHandle owner = new UserHandle(userId);
2965 final String uuid = null;
Jeff Sharkey48877892015-03-18 11:27:19 -07002966 final String state = Environment.MEDIA_REMOVED;
2967
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07002968 res.add(0, new StorageVolume(id, StorageVolume.STORAGE_ID_INVALID, path,
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002969 description, primary, removable, emulated, mtpReserveSize,
2970 allowMassStorage, maxFileSize, owner, uuid, state));
Jeff Sharkey48877892015-03-18 11:27:19 -07002971 }
2972
2973 return res.toArray(new StorageVolume[res.size()]);
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002974 }
2975
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002976 @Override
2977 public DiskInfo[] getDisks() {
2978 synchronized (mLock) {
2979 final DiskInfo[] res = new DiskInfo[mDisks.size()];
2980 for (int i = 0; i < mDisks.size(); i++) {
2981 res[i] = mDisks.valueAt(i);
2982 }
2983 return res;
2984 }
2985 }
2986
2987 @Override
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07002988 public VolumeInfo[] getVolumes(int flags) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002989 synchronized (mLock) {
2990 final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
2991 for (int i = 0; i < mVolumes.size(); i++) {
2992 res[i] = mVolumes.valueAt(i);
2993 }
2994 return res;
2995 }
2996 }
2997
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07002998 @Override
2999 public VolumeRecord[] getVolumeRecords(int flags) {
3000 synchronized (mLock) {
3001 final VolumeRecord[] res = new VolumeRecord[mRecords.size()];
3002 for (int i = 0; i < mRecords.size(); i++) {
3003 res[i] = mRecords.valueAt(i);
3004 }
3005 return res;
3006 }
3007 }
3008
Kenny Rootaf9d6672010-10-08 09:21:39 -07003009 private void addObbStateLocked(ObbState obbState) throws RemoteException {
3010 final IBinder binder = obbState.getBinder();
3011 List<ObbState> obbStates = mObbMounts.get(binder);
Kenny Root5919ac62010-10-05 09:49:40 -07003012
Kenny Rootaf9d6672010-10-08 09:21:39 -07003013 if (obbStates == null) {
3014 obbStates = new ArrayList<ObbState>();
3015 mObbMounts.put(binder, obbStates);
3016 } else {
3017 for (final ObbState o : obbStates) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003018 if (o.rawPath.equals(obbState.rawPath)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003019 throw new IllegalStateException("Attempt to add ObbState twice. "
3020 + "This indicates an error in the MountService logic.");
Kenny Root5919ac62010-10-05 09:49:40 -07003021 }
3022 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003023 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003024
3025 obbStates.add(obbState);
3026 try {
3027 obbState.link();
3028 } catch (RemoteException e) {
3029 /*
3030 * The binder died before we could link it, so clean up our state
3031 * and return failure.
3032 */
3033 obbStates.remove(obbState);
3034 if (obbStates.isEmpty()) {
3035 mObbMounts.remove(binder);
3036 }
3037
3038 // Rethrow the error so mountObb can get it
3039 throw e;
3040 }
3041
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003042 mObbPathToStateMap.put(obbState.rawPath, obbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003043 }
3044
Kenny Rootaf9d6672010-10-08 09:21:39 -07003045 private void removeObbStateLocked(ObbState obbState) {
3046 final IBinder binder = obbState.getBinder();
3047 final List<ObbState> obbStates = mObbMounts.get(binder);
3048 if (obbStates != null) {
3049 if (obbStates.remove(obbState)) {
3050 obbState.unlink();
Kenny Root05105f72010-09-22 17:29:43 -07003051 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003052 if (obbStates.isEmpty()) {
3053 mObbMounts.remove(binder);
3054 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003055 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003056
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003057 mObbPathToStateMap.remove(obbState.rawPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003058 }
3059
Kenny Roota02b8b02010-08-05 16:14:17 -07003060 private class ObbActionHandler extends Handler {
3061 private boolean mBound = false;
Kenny Root480afe72010-10-07 10:17:50 -07003062 private final List<ObbAction> mActions = new LinkedList<ObbAction>();
Kenny Roota02b8b02010-08-05 16:14:17 -07003063
3064 ObbActionHandler(Looper l) {
3065 super(l);
3066 }
3067
3068 @Override
3069 public void handleMessage(Message msg) {
3070 switch (msg.what) {
3071 case OBB_RUN_ACTION: {
Kenny Root480afe72010-10-07 10:17:50 -07003072 final ObbAction action = (ObbAction) msg.obj;
Kenny Roota02b8b02010-08-05 16:14:17 -07003073
3074 if (DEBUG_OBB)
3075 Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
3076
3077 // If a bind was already initiated we don't really
3078 // need to do anything. The pending install
3079 // will be processed later on.
3080 if (!mBound) {
3081 // If this is the only one pending we might
3082 // have to bind to the service again.
3083 if (!connectToService()) {
3084 Slog.e(TAG, "Failed to bind to media container service");
3085 action.handleError();
3086 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003087 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003088 }
Kenny Root735de3b2010-09-30 14:11:39 -07003089
Kenny Root735de3b2010-09-30 14:11:39 -07003090 mActions.add(action);
Kenny Roota02b8b02010-08-05 16:14:17 -07003091 break;
3092 }
3093 case OBB_MCS_BOUND: {
3094 if (DEBUG_OBB)
3095 Slog.i(TAG, "OBB_MCS_BOUND");
3096 if (msg.obj != null) {
3097 mContainerService = (IMediaContainerService) msg.obj;
3098 }
3099 if (mContainerService == null) {
3100 // Something seriously wrong. Bail out
3101 Slog.e(TAG, "Cannot bind to media container service");
3102 for (ObbAction action : mActions) {
3103 // Indicate service bind error
3104 action.handleError();
3105 }
3106 mActions.clear();
3107 } else if (mActions.size() > 0) {
Kenny Root480afe72010-10-07 10:17:50 -07003108 final ObbAction action = mActions.get(0);
Kenny Roota02b8b02010-08-05 16:14:17 -07003109 if (action != null) {
3110 action.execute(this);
3111 }
3112 } else {
3113 // Should never happen ideally.
3114 Slog.w(TAG, "Empty queue");
3115 }
3116 break;
3117 }
3118 case OBB_MCS_RECONNECT: {
3119 if (DEBUG_OBB)
3120 Slog.i(TAG, "OBB_MCS_RECONNECT");
3121 if (mActions.size() > 0) {
3122 if (mBound) {
3123 disconnectService();
3124 }
3125 if (!connectToService()) {
3126 Slog.e(TAG, "Failed to bind to media container service");
3127 for (ObbAction action : mActions) {
3128 // Indicate service bind error
3129 action.handleError();
3130 }
3131 mActions.clear();
3132 }
3133 }
3134 break;
3135 }
3136 case OBB_MCS_UNBIND: {
3137 if (DEBUG_OBB)
3138 Slog.i(TAG, "OBB_MCS_UNBIND");
3139
3140 // Delete pending install
3141 if (mActions.size() > 0) {
3142 mActions.remove(0);
3143 }
3144 if (mActions.size() == 0) {
3145 if (mBound) {
3146 disconnectService();
3147 }
3148 } else {
3149 // There are more pending requests in queue.
3150 // Just post MCS_BOUND message to trigger processing
3151 // of next pending install.
3152 mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
3153 }
3154 break;
3155 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003156 case OBB_FLUSH_MOUNT_STATE: {
3157 final String path = (String) msg.obj;
3158
3159 if (DEBUG_OBB)
3160 Slog.i(TAG, "Flushing all OBB state for path " + path);
3161
3162 synchronized (mObbMounts) {
3163 final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
3164
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003165 final Iterator<ObbState> i = mObbPathToStateMap.values().iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003166 while (i.hasNext()) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003167 final ObbState state = i.next();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003168
3169 /*
3170 * If this entry's source file is in the volume path
3171 * that got unmounted, remove it because it's no
3172 * longer valid.
3173 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003174 if (state.canonicalPath.startsWith(path)) {
3175 obbStatesToRemove.add(state);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003176 }
3177 }
3178
3179 for (final ObbState obbState : obbStatesToRemove) {
3180 if (DEBUG_OBB)
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003181 Slog.i(TAG, "Removing state for " + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003182
3183 removeObbStateLocked(obbState);
3184
3185 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003186 obbState.token.onObbResult(obbState.rawPath, obbState.nonce,
Kenny Rootaf9d6672010-10-08 09:21:39 -07003187 OnObbStateChangeListener.UNMOUNTED);
3188 } catch (RemoteException e) {
3189 Slog.i(TAG, "Couldn't send unmount notification for OBB: "
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003190 + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003191 }
3192 }
3193 }
3194 break;
3195 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003196 }
3197 }
3198
3199 private boolean connectToService() {
3200 if (DEBUG_OBB)
3201 Slog.i(TAG, "Trying to bind to DefaultContainerService");
3202
3203 Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Jeff Sharkey6dce4962015-07-03 18:08:41 -07003204 if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE,
Xiaohui Chene4de5a02015-09-22 15:33:31 -07003205 UserHandle.SYSTEM)) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003206 mBound = true;
3207 return true;
3208 }
3209 return false;
3210 }
3211
3212 private void disconnectService() {
3213 mContainerService = null;
3214 mBound = false;
3215 mContext.unbindService(mDefContainerConn);
3216 }
3217 }
3218
3219 abstract class ObbAction {
3220 private static final int MAX_RETRIES = 3;
3221 private int mRetries;
3222
3223 ObbState mObbState;
3224
3225 ObbAction(ObbState obbState) {
3226 mObbState = obbState;
3227 }
3228
3229 public void execute(ObbActionHandler handler) {
3230 try {
3231 if (DEBUG_OBB)
Ben Komalo444eca22011-09-01 15:17:44 -07003232 Slog.i(TAG, "Starting to execute action: " + toString());
Kenny Roota02b8b02010-08-05 16:14:17 -07003233 mRetries++;
3234 if (mRetries > MAX_RETRIES) {
3235 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
Kenny Root480afe72010-10-07 10:17:50 -07003236 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003237 handleError();
Kenny Roota02b8b02010-08-05 16:14:17 -07003238 } else {
3239 handleExecute();
3240 if (DEBUG_OBB)
3241 Slog.i(TAG, "Posting install MCS_UNBIND");
3242 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
3243 }
3244 } catch (RemoteException e) {
3245 if (DEBUG_OBB)
3246 Slog.i(TAG, "Posting install MCS_RECONNECT");
3247 mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
3248 } catch (Exception e) {
3249 if (DEBUG_OBB)
3250 Slog.d(TAG, "Error handling OBB action", e);
3251 handleError();
Kenny Root17eb6fb2010-10-06 15:02:52 -07003252 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003253 }
3254 }
3255
Kenny Root05105f72010-09-22 17:29:43 -07003256 abstract void handleExecute() throws RemoteException, IOException;
Kenny Roota02b8b02010-08-05 16:14:17 -07003257 abstract void handleError();
Kenny Root38cf8862010-09-26 14:18:51 -07003258
3259 protected ObbInfo getObbInfo() throws IOException {
3260 ObbInfo obbInfo;
3261 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003262 obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003263 } catch (RemoteException e) {
3264 Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003265 + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003266 obbInfo = null;
3267 }
3268 if (obbInfo == null) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003269 throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003270 }
3271 return obbInfo;
3272 }
3273
Kenny Rootaf9d6672010-10-08 09:21:39 -07003274 protected void sendNewStatusOrIgnore(int status) {
3275 if (mObbState == null || mObbState.token == null) {
3276 return;
3277 }
3278
Kenny Root38cf8862010-09-26 14:18:51 -07003279 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003280 mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
Kenny Root38cf8862010-09-26 14:18:51 -07003281 } catch (RemoteException e) {
3282 Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
3283 }
3284 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003285 }
3286
3287 class MountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003288 private final String mKey;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003289 private final int mCallingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003290
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003291 MountObbAction(ObbState obbState, String key, int callingUid) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003292 super(obbState);
3293 mKey = key;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003294 mCallingUid = callingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003295 }
3296
Jason parks5af0b912010-11-29 09:05:25 -06003297 @Override
Kenny Root735de3b2010-09-30 14:11:39 -07003298 public void handleExecute() throws IOException, RemoteException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003299 waitForReady();
3300 warnOnNotMounted();
3301
Kenny Root38cf8862010-09-26 14:18:51 -07003302 final ObbInfo obbInfo = getObbInfo();
3303
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003304 if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003305 Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
3306 + " which is owned by " + obbInfo.packageName);
3307 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3308 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003309 }
3310
Kenny Rootaf9d6672010-10-08 09:21:39 -07003311 final boolean isMounted;
3312 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003313 isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003314 }
3315 if (isMounted) {
3316 Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
3317 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
3318 return;
3319 }
3320
Kenny Rootaf9d6672010-10-08 09:21:39 -07003321 final String hashedKey;
3322 if (mKey == null) {
3323 hashedKey = "none";
3324 } else {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003325 try {
Kenny Root3b1abba2010-10-13 15:00:07 -07003326 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
3327
3328 KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
3329 PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
3330 SecretKey key = factory.generateSecret(ks);
3331 BigInteger bi = new BigInteger(key.getEncoded());
3332 hashedKey = bi.toString(16);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003333 } catch (NoSuchAlgorithmException e) {
Kenny Root3b1abba2010-10-13 15:00:07 -07003334 Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
3335 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
3336 return;
3337 } catch (InvalidKeySpecException e) {
3338 Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
3339 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root38cf8862010-09-26 14:18:51 -07003340 return;
3341 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003342 }
Kenny Root38cf8862010-09-26 14:18:51 -07003343
Kenny Rootaf9d6672010-10-08 09:21:39 -07003344 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003345 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003346 mConnector.execute("obb", "mount", mObbState.canonicalPath, new SensitiveArg(hashedKey),
Jeff Sharkey56cd6462013-06-07 15:09:15 -07003347 mObbState.ownerGid);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003348 } catch (NativeDaemonConnectorException e) {
3349 int code = e.getCode();
3350 if (code != VoldResponseCode.OpFailedStorageBusy) {
3351 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003352 }
3353 }
3354
Kenny Rootaf9d6672010-10-08 09:21:39 -07003355 if (rc == StorageResultCode.OperationSucceeded) {
3356 if (DEBUG_OBB)
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003357 Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003358
3359 synchronized (mObbMounts) {
3360 addObbStateLocked(mObbState);
3361 }
3362
3363 sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
Kenny Root02c87302010-07-01 08:10:18 -07003364 } else {
Kenny Root05105f72010-09-22 17:29:43 -07003365 Slog.e(TAG, "Couldn't mount OBB file: " + rc);
Kenny Roota02b8b02010-08-05 16:14:17 -07003366
Kenny Rootaf9d6672010-10-08 09:21:39 -07003367 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
Kenny Root02c87302010-07-01 08:10:18 -07003368 }
3369 }
3370
Jason parks5af0b912010-11-29 09:05:25 -06003371 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003372 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003373 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root02c87302010-07-01 08:10:18 -07003374 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003375
3376 @Override
3377 public String toString() {
3378 StringBuilder sb = new StringBuilder();
3379 sb.append("MountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003380 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003381 sb.append('}');
3382 return sb.toString();
3383 }
3384 }
3385
3386 class UnmountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003387 private final boolean mForceUnmount;
Kenny Roota02b8b02010-08-05 16:14:17 -07003388
3389 UnmountObbAction(ObbState obbState, boolean force) {
3390 super(obbState);
3391 mForceUnmount = force;
3392 }
3393
Jason parks5af0b912010-11-29 09:05:25 -06003394 @Override
Kenny Root38cf8862010-09-26 14:18:51 -07003395 public void handleExecute() throws IOException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003396 waitForReady();
3397 warnOnNotMounted();
3398
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003399 final ObbState existingState;
Kenny Root38cf8862010-09-26 14:18:51 -07003400 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003401 existingState = mObbPathToStateMap.get(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003402 }
Kenny Root38cf8862010-09-26 14:18:51 -07003403
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003404 if (existingState == null) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003405 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
3406 return;
3407 }
3408
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003409 if (existingState.ownerGid != mObbState.ownerGid) {
3410 Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
3411 + " (owned by GID " + existingState.ownerGid + ")");
Kenny Rootaf9d6672010-10-08 09:21:39 -07003412 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3413 return;
3414 }
3415
Kenny Rootaf9d6672010-10-08 09:21:39 -07003416 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003417 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003418 final Command cmd = new Command("obb", "unmount", mObbState.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08003419 if (mForceUnmount) {
3420 cmd.appendArg("force");
3421 }
3422 mConnector.execute(cmd);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003423 } catch (NativeDaemonConnectorException e) {
3424 int code = e.getCode();
3425 if (code == VoldResponseCode.OpFailedStorageBusy) {
3426 rc = StorageResultCode.OperationFailedStorageBusy;
3427 } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
3428 // If it's not mounted then we've already won.
3429 rc = StorageResultCode.OperationSucceeded;
3430 } else {
3431 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003432 }
3433 }
3434
Kenny Rootaf9d6672010-10-08 09:21:39 -07003435 if (rc == StorageResultCode.OperationSucceeded) {
3436 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003437 removeObbStateLocked(existingState);
Kenny Root38cf8862010-09-26 14:18:51 -07003438 }
3439
Kenny Rootaf9d6672010-10-08 09:21:39 -07003440 sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
Kenny Roota02b8b02010-08-05 16:14:17 -07003441 } else {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003442 Slog.w(TAG, "Could not unmount OBB: " + existingState);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003443 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
Kenny Roota02b8b02010-08-05 16:14:17 -07003444 }
3445 }
3446
Jason parks5af0b912010-11-29 09:05:25 -06003447 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003448 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003449 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Roota02b8b02010-08-05 16:14:17 -07003450 }
3451
3452 @Override
3453 public String toString() {
3454 StringBuilder sb = new StringBuilder();
3455 sb.append("UnmountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003456 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003457 sb.append(",force=");
3458 sb.append(mForceUnmount);
Kenny Roota02b8b02010-08-05 16:14:17 -07003459 sb.append('}');
3460 return sb.toString();
3461 }
Kenny Root02c87302010-07-01 08:10:18 -07003462 }
Kenny Root38cf8862010-09-26 14:18:51 -07003463
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003464 private static class Callbacks extends Handler {
3465 private static final int MSG_STORAGE_STATE_CHANGED = 1;
3466 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003467 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
3468 private static final int MSG_VOLUME_FORGOTTEN = 4;
3469 private static final int MSG_DISK_SCANNED = 5;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003470 private static final int MSG_DISK_DESTROYED = 6;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003471
3472 private final RemoteCallbackList<IMountServiceListener>
3473 mCallbacks = new RemoteCallbackList<>();
3474
3475 public Callbacks(Looper looper) {
3476 super(looper);
3477 }
3478
3479 public void register(IMountServiceListener callback) {
3480 mCallbacks.register(callback);
3481 }
3482
3483 public void unregister(IMountServiceListener callback) {
3484 mCallbacks.unregister(callback);
3485 }
3486
3487 @Override
3488 public void handleMessage(Message msg) {
3489 final SomeArgs args = (SomeArgs) msg.obj;
3490 final int n = mCallbacks.beginBroadcast();
3491 for (int i = 0; i < n; i++) {
3492 final IMountServiceListener callback = mCallbacks.getBroadcastItem(i);
3493 try {
3494 invokeCallback(callback, msg.what, args);
3495 } catch (RemoteException ignored) {
3496 }
3497 }
3498 mCallbacks.finishBroadcast();
3499 args.recycle();
3500 }
3501
3502 private void invokeCallback(IMountServiceListener callback, int what, SomeArgs args)
3503 throws RemoteException {
3504 switch (what) {
3505 case MSG_STORAGE_STATE_CHANGED: {
3506 callback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
3507 (String) args.arg3);
3508 break;
3509 }
3510 case MSG_VOLUME_STATE_CHANGED: {
3511 callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
3512 break;
3513 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07003514 case MSG_VOLUME_RECORD_CHANGED: {
3515 callback.onVolumeRecordChanged((VolumeRecord) args.arg1);
3516 break;
3517 }
3518 case MSG_VOLUME_FORGOTTEN: {
3519 callback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003520 break;
3521 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003522 case MSG_DISK_SCANNED: {
3523 callback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003524 break;
3525 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003526 case MSG_DISK_DESTROYED: {
3527 callback.onDiskDestroyed((DiskInfo) args.arg1);
3528 break;
3529 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003530 }
3531 }
3532
3533 private void notifyStorageStateChanged(String path, String oldState, String newState) {
3534 final SomeArgs args = SomeArgs.obtain();
3535 args.arg1 = path;
3536 args.arg2 = oldState;
3537 args.arg3 = newState;
3538 obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
3539 }
3540
3541 private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
3542 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003543 args.arg1 = vol.clone();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003544 args.argi2 = oldState;
3545 args.argi3 = newState;
3546 obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
3547 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003548
Jeff Sharkey50a05452015-04-29 11:24:52 -07003549 private void notifyVolumeRecordChanged(VolumeRecord rec) {
3550 final SomeArgs args = SomeArgs.obtain();
3551 args.arg1 = rec.clone();
3552 obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
3553 }
3554
3555 private void notifyVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003556 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003557 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003558 obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003559 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003560
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003561 private void notifyDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003562 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003563 args.arg1 = disk.clone();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003564 args.argi2 = volumeCount;
3565 obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003566 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003567
3568 private void notifyDiskDestroyed(DiskInfo disk) {
3569 final SomeArgs args = SomeArgs.obtain();
3570 args.arg1 = disk.clone();
3571 obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
3572 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003573 }
3574
Kenny Root38cf8862010-09-26 14:18:51 -07003575 @Override
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003576 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
3577 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
3578
3579 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003580 synchronized (mLock) {
3581 pw.println("Disks:");
3582 pw.increaseIndent();
3583 for (int i = 0; i < mDisks.size(); i++) {
3584 final DiskInfo disk = mDisks.valueAt(i);
3585 disk.dump(pw);
3586 }
3587 pw.decreaseIndent();
3588
3589 pw.println();
3590 pw.println("Volumes:");
3591 pw.increaseIndent();
3592 for (int i = 0; i < mVolumes.size(); i++) {
3593 final VolumeInfo vol = mVolumes.valueAt(i);
3594 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue;
3595 vol.dump(pw);
3596 }
3597 pw.decreaseIndent();
3598
3599 pw.println();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003600 pw.println("Records:");
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003601 pw.increaseIndent();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003602 for (int i = 0; i < mRecords.size(); i++) {
3603 final VolumeRecord note = mRecords.valueAt(i);
3604 note.dump(pw);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003605 }
3606 pw.decreaseIndent();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07003607
3608 pw.println();
3609 pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07003610 pw.println("Force adoptable: " + mForceAdoptable);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08003611 pw.println();
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003612 pw.println("Local unlocked users: " + Arrays.toString(mLocalUnlockedUsers));
3613 pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003614 }
Kenny Root38cf8862010-09-26 14:18:51 -07003615
Kenny Root38cf8862010-09-26 14:18:51 -07003616 synchronized (mObbMounts) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003617 pw.println();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003618 pw.println("mObbMounts:");
3619 pw.increaseIndent();
3620 final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet()
3621 .iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003622 while (binders.hasNext()) {
3623 Entry<IBinder, List<ObbState>> e = binders.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003624 pw.println(e.getKey() + ":");
3625 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003626 final List<ObbState> obbStates = e.getValue();
Kenny Root38cf8862010-09-26 14:18:51 -07003627 for (final ObbState obbState : obbStates) {
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003628 pw.println(obbState);
Kenny Root38cf8862010-09-26 14:18:51 -07003629 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003630 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003631 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003632 pw.decreaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003633
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003634 pw.println();
3635 pw.println("mObbPathToStateMap:");
3636 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003637 final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
3638 while (maps.hasNext()) {
3639 final Entry<String, ObbState> e = maps.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003640 pw.print(e.getKey());
3641 pw.print(" -> ");
3642 pw.println(e.getValue());
Kenny Rootaf9d6672010-10-08 09:21:39 -07003643 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003644 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003645 }
Kenny Root4161f9b2011-07-13 09:48:33 -07003646
Robert Greenwalt470fd722012-01-18 12:51:15 -08003647 pw.println();
Jeff Sharkey5b0e5202015-12-18 17:18:09 -07003648 pw.println("mConnector:");
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003649 pw.increaseIndent();
Robert Greenwalt470fd722012-01-18 12:51:15 -08003650 mConnector.dump(fd, pw, args);
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003651 pw.decreaseIndent();
Christopher Tate7265abe2014-11-21 13:54:45 -08003652
Christopher Tate7265abe2014-11-21 13:54:45 -08003653 pw.println();
Jeff Sharkey5b0e5202015-12-18 17:18:09 -07003654 pw.println("mCryptConnector:");
3655 pw.increaseIndent();
3656 mCryptConnector.dump(fd, pw, args);
3657 pw.decreaseIndent();
3658
3659 pw.println();
Christopher Tate7265abe2014-11-21 13:54:45 -08003660 pw.print("Last maintenance: ");
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07003661 pw.println(TimeUtils.formatForLogging(mLastMaintenance));
Kenny Root38cf8862010-09-26 14:18:51 -07003662 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003663
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003664 /** {@inheritDoc} */
Jeff Sharkey48877892015-03-18 11:27:19 -07003665 @Override
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003666 public void monitor() {
3667 if (mConnector != null) {
3668 mConnector.monitor();
3669 }
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07003670 if (mCryptConnector != null) {
3671 mCryptConnector.monitor();
3672 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003673 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003674
3675 private final class MountServiceInternalImpl extends MountServiceInternal {
3676 // Not guarded by a lock.
3677 private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
3678 new CopyOnWriteArrayList<>();
3679
3680 @Override
3681 public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
3682 // No locking - CopyOnWriteArrayList
3683 mPolicies.add(policy);
3684 }
3685
3686 @Override
3687 public void onExternalStoragePolicyChanged(int uid, String packageName) {
3688 final int mountMode = getExternalStorageMountMode(uid, packageName);
3689 remountUidExternalStorage(uid, mountMode);
3690 }
3691
3692 @Override
3693 public int getExternalStorageMountMode(int uid, String packageName) {
3694 // No locking - CopyOnWriteArrayList
3695 int mountMode = Integer.MAX_VALUE;
3696 for (ExternalStorageMountPolicy policy : mPolicies) {
3697 final int policyMode = policy.getMountMode(uid, packageName);
3698 if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
3699 return Zygote.MOUNT_EXTERNAL_NONE;
3700 }
3701 mountMode = Math.min(mountMode, policyMode);
3702 }
3703 if (mountMode == Integer.MAX_VALUE) {
3704 return Zygote.MOUNT_EXTERNAL_NONE;
3705 }
3706 return mountMode;
3707 }
3708
3709 public boolean hasExternalStorage(int uid, String packageName) {
Amith Yamasani2bd5cff2015-07-22 14:42:31 -07003710 // No need to check for system uid. This avoids a deadlock between
3711 // PackageManagerService and AppOpsService.
3712 if (uid == Process.SYSTEM_UID) {
3713 return true;
3714 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003715 // No locking - CopyOnWriteArrayList
3716 for (ExternalStorageMountPolicy policy : mPolicies) {
3717 final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
3718 if (!policyHasStorage) {
3719 return false;
3720 }
3721 }
3722 return true;
3723 }
3724 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003725}