blob: 8c8be4e64650b9829e0845bf7b6cea0c980055ca [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;
21import static com.android.internal.util.XmlUtils.readStringAttribute;
Jeff Sharkey4c099d02015-05-15 13:45:00 -070022import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070023import static com.android.internal.util.XmlUtils.writeIntAttribute;
24import static com.android.internal.util.XmlUtils.writeStringAttribute;
25import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
26import static org.xmlpull.v1.XmlPullParser.START_TAG;
27
Jason parks8888c592011-01-20 22:46:41 -060028import android.Manifest;
Elliott Hughesf839b4f2014-09-26 12:30:47 -070029import android.app.ActivityManagerNative;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -070030import android.app.AppOpsManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070031import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.content.Context;
33import android.content.Intent;
Kenny Roota02b8b02010-08-05 16:14:17 -070034import android.content.ServiceConnection;
Jeff Sharkey275e3e42015-04-24 16:10:32 -070035import android.content.pm.IPackageMoveObserver;
36import android.content.pm.PackageManager;
Elliott Hughesf839b4f2014-09-26 12:30:47 -070037import android.content.res.Configuration;
Kenny Root02c87302010-07-01 08:10:18 -070038import android.content.res.ObbInfo;
Jeff Sharkey48877892015-03-18 11:27:19 -070039import android.mtp.MtpStorage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.net.Uri;
Kenny Root02c87302010-07-01 08:10:18 -070041import android.os.Binder;
Jeff Sharkey4c099d02015-05-15 13:45:00 -070042import android.os.DropBoxManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070043import android.os.Environment;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070044import android.os.Environment.UserEnvironment;
Jeff Sharkey48877892015-03-18 11:27:19 -070045import android.os.FileUtils;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080046import android.os.Handler;
Dianne Hackbornefa92b22013-05-03 14:11:43 -070047import android.os.HandlerThread;
Kenny Roota02b8b02010-08-05 16:14:17 -070048import android.os.IBinder;
Daniel Sandler5f27ef42010-03-16 15:42:02 -040049import android.os.Looper;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080050import android.os.Message;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070051import android.os.RemoteCallbackList;
San Mehat4270e1e2010-01-29 05:32:19 -080052import android.os.RemoteException;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -080053import android.os.ServiceManager;
Svetoslavf23b64d2013-04-25 14:45:54 -070054import android.os.SystemClock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070056import android.os.UserHandle;
Emily Bernier92aa5a22014-07-07 10:11:48 -040057import android.os.UserManager;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070058import android.os.storage.DiskInfo;
Kenny Roota02b8b02010-08-05 16:14:17 -070059import android.os.storage.IMountService;
60import android.os.storage.IMountServiceListener;
61import android.os.storage.IMountShutdownObserver;
62import android.os.storage.IObbActionListener;
Kenny Rootaf9d6672010-10-08 09:21:39 -070063import android.os.storage.OnObbStateChangeListener;
Paul Lawrence46791e72014-04-03 09:10:26 -070064import android.os.storage.StorageManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070065import android.os.storage.StorageResultCode;
Mike Lockwood2f6a3882011-05-09 19:08:06 -070066import android.os.storage.StorageVolume;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070067import android.os.storage.VolumeInfo;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070068import android.os.storage.VolumeRecord;
Jason parksf7b3cd42011-01-27 09:28:25 -060069import android.text.TextUtils;
Jeff Sharkey1783f142015-04-17 10:52:51 -070070import android.text.format.DateUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -070071import android.util.ArrayMap;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070072import android.util.AtomicFile;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070073import android.util.Log;
San Mehata5078592010-03-25 09:36:54 -070074import android.util.Slog;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070075import android.util.Xml;
Jeff Sharkey48877892015-03-18 11:27:19 -070076
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070077import libcore.io.IoUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -070078import libcore.util.EmptyArray;
79import libcore.util.HexEncoding;
Mike Lockwood2f6a3882011-05-09 19:08:06 -070080
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -080081import com.android.internal.annotations.GuardedBy;
82import com.android.internal.annotations.VisibleForTesting;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070083import com.android.internal.app.IMediaContainerService;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070084import com.android.internal.os.SomeArgs;
Jeff Sharkey48877892015-03-18 11:27:19 -070085import com.android.internal.util.ArrayUtils;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070086import com.android.internal.util.FastXmlSerializer;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -070087import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -070088import com.android.internal.util.Preconditions;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070089import com.android.server.NativeDaemonConnector.Command;
Jeff Sharkey56cd6462013-06-07 15:09:15 -070090import com.android.server.NativeDaemonConnector.SensitiveArg;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070091import com.android.server.pm.PackageManagerService;
Kenny Roota02b8b02010-08-05 16:14:17 -070092
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070093import org.xmlpull.v1.XmlPullParser;
94import org.xmlpull.v1.XmlPullParserException;
95import org.xmlpull.v1.XmlSerializer;
96
Jeff Sharkeyb049e212012-09-07 23:16:01 -070097import java.io.File;
Kenny Root38cf8862010-09-26 14:18:51 -070098import java.io.FileDescriptor;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070099import java.io.FileInputStream;
100import java.io.FileNotFoundException;
Christopher Tate7265abe2014-11-21 13:54:45 -0800101import java.io.FileOutputStream;
Kenny Root05105f72010-09-22 17:29:43 -0700102import java.io.IOException;
Kenny Root38cf8862010-09-26 14:18:51 -0700103import java.io.PrintWriter;
Kenny Root3b1abba2010-10-13 15:00:07 -0700104import java.math.BigInteger;
Paul Lawrence8e397362014-01-27 15:22:30 -0800105import java.nio.charset.StandardCharsets;
Kenny Root735de3b2010-09-30 14:11:39 -0700106import java.security.NoSuchAlgorithmException;
Kenny Root3b1abba2010-10-13 15:00:07 -0700107import java.security.spec.InvalidKeySpecException;
108import java.security.spec.KeySpec;
Christopher Tate7265abe2014-11-21 13:54:45 -0800109import java.text.SimpleDateFormat;
San Mehat22dd86e2010-01-12 12:21:18 -0800110import java.util.ArrayList;
Christopher Tate7265abe2014-11-21 13:54:45 -0800111import java.util.Date;
Kenny Roota02b8b02010-08-05 16:14:17 -0700112import java.util.HashMap;
San Mehat6cdd9c02010-02-09 14:45:20 -0800113import java.util.HashSet;
Kenny Root38cf8862010-09-26 14:18:51 -0700114import java.util.Iterator;
Kenny Roota02b8b02010-08-05 16:14:17 -0700115import java.util.LinkedList;
116import java.util.List;
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700117import java.util.Locale;
Kenny Roota02b8b02010-08-05 16:14:17 -0700118import java.util.Map;
Kenny Root38cf8862010-09-26 14:18:51 -0700119import java.util.Map.Entry;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700120import java.util.Objects;
Kenny Root51a573c2012-05-17 13:30:28 -0700121import java.util.concurrent.CountDownLatch;
122import java.util.concurrent.TimeUnit;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123
Kenny Root3b1abba2010-10-13 15:00:07 -0700124import javax.crypto.SecretKey;
125import javax.crypto.SecretKeyFactory;
126import javax.crypto.spec.PBEKeySpec;
127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128/**
Jeff Sharkey48877892015-03-18 11:27:19 -0700129 * Service responsible for various storage media. Connects to {@code vold} to
130 * watch for and manage dynamically added storage, such as SD cards and USB mass
131 * storage. Also decides how storage should be presented to users on the device.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 */
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700133class MountService extends IMountService.Stub
134 implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
Jason parks5af0b912010-11-29 09:05:25 -0600135
Jeff Sharkey48877892015-03-18 11:27:19 -0700136 // TODO: finish enforcing UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA
137
Christopher Tated417d622013-08-19 16:14:25 -0700138 // Static direct instance pointer for the tightly-coupled idle service to use
139 static MountService sSelf = null;
140
Jeff Sharkey56e62932015-03-21 20:41:00 -0700141 public static class Lifecycle extends SystemService {
142 private MountService mMountService;
143
144 public Lifecycle(Context context) {
145 super(context);
146 }
147
148 @Override
149 public void onStart() {
150 mMountService = new MountService(getContext());
151 publishBinderService("mount", mMountService);
152 }
153
154 @Override
155 public void onBootPhase(int phase) {
156 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
157 mMountService.systemReady();
158 }
159 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700160
161 @Override
162 public void onStartUser(int userHandle) {
163 mMountService.onStartUser(userHandle);
164 }
165
166 @Override
167 public void onCleanupUser(int userHandle) {
168 mMountService.onCleanupUser(userHandle);
169 }
Jeff Sharkey56e62932015-03-21 20:41:00 -0700170 }
171
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800172 private static final boolean LOCAL_LOGD = false;
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800173 private static final boolean DEBUG_EVENTS = false;
Kenny Rootb7db2722011-01-25 16:39:35 -0800174 private static final boolean DEBUG_OBB = false;
Kenny Root02c87302010-07-01 08:10:18 -0700175
Kenny Root07714d42011-08-17 17:49:28 -0700176 // Disable this since it messes up long-running cryptfs operations.
177 private static final boolean WATCHDOG_ENABLE = false;
178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 private static final String TAG = "MountService";
Jeff Sharkey9756d752015-05-14 21:07:42 -0700180 private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181
Kenny Root305bcbf2010-09-03 07:56:38 -0700182 private static final String VOLD_TAG = "VoldConnector";
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700183 private static final String CRYPTD_TAG = "CryptdConnector";
Kenny Root305bcbf2010-09-03 07:56:38 -0700184
Kenny Rootcf0b38c2011-03-22 14:17:59 -0700185 /** Maximum number of ASEC containers allowed to be mounted. */
186 private static final int MAX_CONTAINERS = 250;
187
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700188 /** Magic value sent by MoveTask.cpp */
189 private static final int MOVE_STATUS_COPY_FINISHED = 82;
190
San Mehat4270e1e2010-01-29 05:32:19 -0800191 /*
192 * Internal vold response code constants
193 */
San Mehat22dd86e2010-01-12 12:21:18 -0800194 class VoldResponseCode {
San Mehat4270e1e2010-01-29 05:32:19 -0800195 /*
196 * 100 series - Requestion action was initiated; expect another reply
197 * before proceeding with a new command.
198 */
San Mehat22dd86e2010-01-12 12:21:18 -0800199 public static final int VolumeListResult = 110;
200 public static final int AsecListResult = 111;
San Mehatc1b4ce92010-02-16 17:13:03 -0800201 public static final int StorageUsersListResult = 112;
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700202 public static final int CryptfsGetfieldResult = 113;
San Mehat22dd86e2010-01-12 12:21:18 -0800203
San Mehat4270e1e2010-01-29 05:32:19 -0800204 /*
205 * 200 series - Requestion action has been successfully completed.
206 */
207 public static final int ShareStatusResult = 210;
San Mehat22dd86e2010-01-12 12:21:18 -0800208 public static final int AsecPathResult = 211;
San Mehat4270e1e2010-01-29 05:32:19 -0800209 public static final int ShareEnabledResult = 212;
San Mehat22dd86e2010-01-12 12:21:18 -0800210
San Mehat4270e1e2010-01-29 05:32:19 -0800211 /*
212 * 400 series - Command was accepted, but the requested action
213 * did not take place.
214 */
215 public static final int OpFailedNoMedia = 401;
216 public static final int OpFailedMediaBlank = 402;
217 public static final int OpFailedMediaCorrupt = 403;
218 public static final int OpFailedVolNotMounted = 404;
San Mehatd9709982010-02-18 11:43:03 -0800219 public static final int OpFailedStorageBusy = 405;
San Mehat2d66cef2010-03-23 11:12:52 -0700220 public static final int OpFailedStorageNotFound = 406;
San Mehat4270e1e2010-01-29 05:32:19 -0800221
222 /*
223 * 600 series - Unsolicited broadcasts.
224 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700225 public static final int DISK_CREATED = 640;
226 public static final int DISK_SIZE_CHANGED = 641;
227 public static final int DISK_LABEL_CHANGED = 642;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700228 public static final int DISK_SCANNED = 643;
Jeff Sharkey48877892015-03-18 11:27:19 -0700229 public static final int DISK_DESTROYED = 649;
230
231 public static final int VOLUME_CREATED = 650;
232 public static final int VOLUME_STATE_CHANGED = 651;
233 public static final int VOLUME_FS_TYPE_CHANGED = 652;
234 public static final int VOLUME_FS_UUID_CHANGED = 653;
235 public static final int VOLUME_FS_LABEL_CHANGED = 654;
236 public static final int VOLUME_PATH_CHANGED = 655;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700237 public static final int VOLUME_INTERNAL_PATH_CHANGED = 656;
Jeff Sharkey48877892015-03-18 11:27:19 -0700238 public static final int VOLUME_DESTROYED = 659;
Svetoslavf23b64d2013-04-25 14:45:54 -0700239
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700240 public static final int MOVE_STATUS = 660;
Jeff Sharkey9756d752015-05-14 21:07:42 -0700241 public static final int BENCHMARK_RESULT = 661;
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700242
Svetoslavf23b64d2013-04-25 14:45:54 -0700243 /*
244 * 700 series - fstrim
245 */
246 public static final int FstrimCompleted = 700;
San Mehat22dd86e2010-01-12 12:21:18 -0800247 }
248
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700249 private static final int VERSION_INIT = 1;
250 private static final int VERSION_ADD_PRIMARY = 2;
Jeff Sharkeyfced5342015-05-10 14:53:34 -0700251 private static final int VERSION_FIX_PRIMARY = 3;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700252
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700253 private static final String TAG_VOLUMES = "volumes";
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700254 private static final String ATTR_VERSION = "version";
255 private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid";
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700256 private static final String ATTR_FORCE_ADOPTABLE = "forceAdoptable";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700257 private static final String TAG_VOLUME = "volume";
258 private static final String ATTR_TYPE = "type";
259 private static final String ATTR_FS_UUID = "fsUuid";
260 private static final String ATTR_NICKNAME = "nickname";
261 private static final String ATTR_USER_FLAGS = "userFlags";
262
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700263 private final AtomicFile mSettingsFile;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700264
Jeff Sharkey48877892015-03-18 11:27:19 -0700265 /**
266 * <em>Never</em> hold the lock while performing downcalls into vold, since
267 * unsolicited events can suddenly appear to update data structures.
268 */
269 private final Object mLock = new Object();
270
271 @GuardedBy("mLock")
272 private int[] mStartedUsers = EmptyArray.INT;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700273
274 /** Map from disk ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700275 @GuardedBy("mLock")
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700276 private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700277 /** Map from volume ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700278 @GuardedBy("mLock")
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700279 private ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
Jeff Sharkey48877892015-03-18 11:27:19 -0700280
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700281 /** Map from UUID to record */
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700282 @GuardedBy("mLock")
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700283 private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>();
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700284 @GuardedBy("mLock")
285 private String mPrimaryStorageUuid;
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700286 @GuardedBy("mLock")
287 private boolean mForceAdoptable;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700288
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700289 /** Map from disk ID to latches */
290 @GuardedBy("mLock")
291 private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
292
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700293 @GuardedBy("mLock")
294 private IPackageMoveObserver mMoveCallback;
295 @GuardedBy("mLock")
296 private String mMoveTargetUuid;
297
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700298 private DiskInfo findDiskById(String id) {
299 synchronized (mLock) {
300 final DiskInfo disk = mDisks.get(id);
301 if (disk != null) {
302 return disk;
303 }
304 }
305 throw new IllegalArgumentException("No disk found for ID " + id);
306 }
307
308 private VolumeInfo findVolumeById(String id) {
309 synchronized (mLock) {
310 final VolumeInfo vol = mVolumes.get(id);
311 if (vol != null) {
312 return vol;
313 }
314 }
315 throw new IllegalArgumentException("No volume found for ID " + id);
316 }
317
Jeff Sharkey48877892015-03-18 11:27:19 -0700318 @Deprecated
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700319 private String findVolumeIdForPath(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700320 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700321 for (int i = 0; i < mVolumes.size(); i++) {
322 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700323 if (vol.path != null && path.startsWith(vol.path)) {
324 return vol.id;
Jeff Sharkey48877892015-03-18 11:27:19 -0700325 }
326 }
327 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700328 throw new IllegalArgumentException("No volume found for path " + path);
Jeff Sharkey48877892015-03-18 11:27:19 -0700329 }
330
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700331 private VolumeInfo findStorageForUuid(String volumeUuid) {
332 final StorageManager storage = mContext.getSystemService(StorageManager.class);
333 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
334 return findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL);
335 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
336 return storage.getPrimaryPhysicalVolume();
337 } else {
338 return storage.findEmulatedForPrivate(storage.findVolumeByUuid(volumeUuid));
339 }
340 }
341
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700342 private CountDownLatch findOrCreateDiskScanLatch(String diskId) {
343 synchronized (mLock) {
344 CountDownLatch latch = mDiskScanLatches.get(diskId);
345 if (latch == null) {
346 latch = new CountDownLatch(1);
347 mDiskScanLatches.put(diskId, latch);
348 }
349 return latch;
350 }
351 }
352
Jeff Sharkey48877892015-03-18 11:27:19 -0700353 private static int sNextMtpIndex = 1;
354
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700355 private static int allocateMtpIndex(String volId) {
356 if (VolumeInfo.ID_EMULATED_INTERNAL.equals(volId)) {
357 return 0;
358 } else {
359 return sNextMtpIndex++;
Jeff Sharkey48877892015-03-18 11:27:19 -0700360 }
361 }
362
Paul Lawrence8e397362014-01-27 15:22:30 -0800363 /** List of crypto types.
364 * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
365 * corresponding commands in CommandListener.cpp */
366 public static final String[] CRYPTO_TYPES
367 = { "password", "default", "pattern", "pin" };
368
Brian Carlstrom7395a8a2014-04-28 22:11:01 -0700369 private final Context mContext;
Brian Carlstromdfad99a2014-05-07 15:21:14 -0700370 private final NativeDaemonConnector mConnector;
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700371 private final NativeDaemonConnector mCryptConnector;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700372
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700373 private volatile boolean mSystemReady = false;
Jeff Sharkey48877892015-03-18 11:27:19 -0700374 private volatile boolean mDaemonConnected = false;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700375
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700376 private PackageManagerService mPms;
377
378 private final Callbacks mCallbacks;
Jeff Sharkey48877892015-03-18 11:27:19 -0700379
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700380 // Two connectors - mConnector & mCryptConnector
381 private final CountDownLatch mConnectedSignal = new CountDownLatch(2);
Jeff Sharkey0be607c2012-11-14 14:39:19 -0800382 private final CountDownLatch mAsecsScanned = new CountDownLatch(1);
Jeff Sharkey48877892015-03-18 11:27:19 -0700383
384 private final Object mUnmountLock = new Object();
385 @GuardedBy("mUnmountLock")
386 private CountDownLatch mUnmountSignal;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800387
San Mehat6cdd9c02010-02-09 14:45:20 -0800388 /**
389 * Private hash of currently mounted secure containers.
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800390 * Used as a lock in methods to manipulate secure containers.
San Mehat6cdd9c02010-02-09 14:45:20 -0800391 */
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800392 final private HashSet<String> mAsecMountSet = new HashSet<String>();
San Mehat6cdd9c02010-02-09 14:45:20 -0800393
Kenny Root02c87302010-07-01 08:10:18 -0700394 /**
Kenny Root3b1abba2010-10-13 15:00:07 -0700395 * The size of the crypto algorithm key in bits for OBB files. Currently
396 * Twofish is used which takes 128-bit keys.
397 */
398 private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
399
400 /**
401 * The number of times to run SHA1 in the PBKDF2 function for OBB files.
402 * 1024 is reasonably secure and not too slow.
403 */
404 private static final int PBKDF2_HASH_ROUNDS = 1024;
405
406 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700407 * Mounted OBB tracking information. Used to track the current state of all
408 * OBBs.
Kenny Root02c87302010-07-01 08:10:18 -0700409 */
Kenny Root735de3b2010-09-30 14:11:39 -0700410 final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700411
412 /** Map from raw paths to {@link ObbState}. */
Kenny Roota02b8b02010-08-05 16:14:17 -0700413 final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
414
415 class ObbState implements IBinder.DeathRecipient {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700416 public ObbState(String rawPath, String canonicalPath, int callingUid,
417 IObbActionListener token, int nonce) {
418 this.rawPath = rawPath;
419 this.canonicalPath = canonicalPath.toString();
420
421 final int userId = UserHandle.getUserId(callingUid);
422 this.ownerPath = buildObbPath(canonicalPath, userId, false);
423 this.voldPath = buildObbPath(canonicalPath, userId, true);
424
425 this.ownerGid = UserHandle.getSharedAppGid(callingUid);
Kenny Rootaf9d6672010-10-08 09:21:39 -0700426 this.token = token;
427 this.nonce = nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700428 }
429
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700430 final String rawPath;
431 final String canonicalPath;
432 final String ownerPath;
433 final String voldPath;
Kenny Roota02b8b02010-08-05 16:14:17 -0700434
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700435 final int ownerGid;
Kenny Roota02b8b02010-08-05 16:14:17 -0700436
Kenny Rootaf9d6672010-10-08 09:21:39 -0700437 // Token of remote Binder caller
438 final IObbActionListener token;
439
440 // Identifier to pass back to the token
441 final int nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700442
Kenny Root735de3b2010-09-30 14:11:39 -0700443 public IBinder getBinder() {
444 return token.asBinder();
445 }
446
Kenny Roota02b8b02010-08-05 16:14:17 -0700447 @Override
448 public void binderDied() {
449 ObbAction action = new UnmountObbAction(this, true);
450 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root735de3b2010-09-30 14:11:39 -0700451 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700452
Kenny Root5919ac62010-10-05 09:49:40 -0700453 public void link() throws RemoteException {
454 getBinder().linkToDeath(this, 0);
455 }
456
457 public void unlink() {
Kenny Root735de3b2010-09-30 14:11:39 -0700458 getBinder().unlinkToDeath(this, 0);
Kenny Roota02b8b02010-08-05 16:14:17 -0700459 }
Kenny Root38cf8862010-09-26 14:18:51 -0700460
461 @Override
462 public String toString() {
463 StringBuilder sb = new StringBuilder("ObbState{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700464 sb.append("rawPath=").append(rawPath);
465 sb.append(",canonicalPath=").append(canonicalPath);
466 sb.append(",ownerPath=").append(ownerPath);
467 sb.append(",voldPath=").append(voldPath);
468 sb.append(",ownerGid=").append(ownerGid);
469 sb.append(",token=").append(token);
470 sb.append(",binder=").append(getBinder());
Kenny Root38cf8862010-09-26 14:18:51 -0700471 sb.append('}');
472 return sb.toString();
473 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700474 }
475
476 // OBB Action Handler
477 final private ObbActionHandler mObbActionHandler;
478
479 // OBB action handler messages
480 private static final int OBB_RUN_ACTION = 1;
481 private static final int OBB_MCS_BOUND = 2;
482 private static final int OBB_MCS_UNBIND = 3;
483 private static final int OBB_MCS_RECONNECT = 4;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700484 private static final int OBB_FLUSH_MOUNT_STATE = 5;
Kenny Roota02b8b02010-08-05 16:14:17 -0700485
486 /*
487 * Default Container Service information
488 */
489 static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
490 "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
491
492 final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
493
494 class DefaultContainerConnection implements ServiceConnection {
Jeff Sharkey48877892015-03-18 11:27:19 -0700495 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700496 public void onServiceConnected(ComponentName name, IBinder service) {
497 if (DEBUG_OBB)
498 Slog.i(TAG, "onServiceConnected");
499 IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
500 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
501 }
502
Jeff Sharkey48877892015-03-18 11:27:19 -0700503 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700504 public void onServiceDisconnected(ComponentName name) {
505 if (DEBUG_OBB)
506 Slog.i(TAG, "onServiceDisconnected");
507 }
508 };
509
510 // Used in the ObbActionHandler
511 private IMediaContainerService mContainerService = null;
Kenny Root02c87302010-07-01 08:10:18 -0700512
Christopher Tate7265abe2014-11-21 13:54:45 -0800513 // Last fstrim operation tracking
514 private static final String LAST_FSTRIM_FILE = "last-fstrim";
515 private final File mLastMaintenanceFile;
516 private long mLastMaintenance;
517
Kenny Root02c87302010-07-01 08:10:18 -0700518 // Handler messages
Jeff Sharkey48877892015-03-18 11:27:19 -0700519 private static final int H_SYSTEM_READY = 1;
520 private static final int H_DAEMON_CONNECTED = 2;
521 private static final int H_SHUTDOWN = 3;
522 private static final int H_FSTRIM = 4;
523 private static final int H_VOLUME_MOUNT = 5;
524 private static final int H_VOLUME_BROADCAST = 6;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800525
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400526 class MountServiceHandler extends Handler {
Jeff Sharkey48877892015-03-18 11:27:19 -0700527 public MountServiceHandler(Looper looper) {
528 super(looper);
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400529 }
530
Jason parks5af0b912010-11-29 09:05:25 -0600531 @Override
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800532 public void handleMessage(Message msg) {
533 switch (msg.what) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700534 case H_SYSTEM_READY: {
Jeff Sharkey48877892015-03-18 11:27:19 -0700535 handleSystemReady();
536 break;
537 }
538 case H_DAEMON_CONNECTED: {
539 handleDaemonConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700540 break;
541 }
Christopher Tated417d622013-08-19 16:14:25 -0700542 case H_FSTRIM: {
Jeff Sharkey1783f142015-04-17 10:52:51 -0700543 if (!isReady()) {
544 Slog.i(TAG, "fstrim requested, but no daemon connection yet; trying again");
Christopher Tate7618db12015-04-28 16:32:55 -0700545 sendMessageDelayed(obtainMessage(H_FSTRIM, msg.obj),
546 DateUtils.SECOND_IN_MILLIS);
547 break;
Jeff Sharkey1783f142015-04-17 10:52:51 -0700548 }
549
Christopher Tated417d622013-08-19 16:14:25 -0700550 Slog.i(TAG, "Running fstrim idle maintenance");
Christopher Tate7265abe2014-11-21 13:54:45 -0800551
552 // Remember when we kicked it off
553 try {
554 mLastMaintenance = System.currentTimeMillis();
555 mLastMaintenanceFile.setLastModified(mLastMaintenance);
556 } catch (Exception e) {
557 Slog.e(TAG, "Unable to record last fstrim!");
558 }
559
Christopher Tated417d622013-08-19 16:14:25 -0700560 try {
561 // This method must be run on the main (handler) thread,
562 // so it is safe to directly call into vold.
563 mConnector.execute("fstrim", "dotrim");
564 EventLogTags.writeFstrimStart(SystemClock.elapsedRealtime());
565 } catch (NativeDaemonConnectorException ndce) {
566 Slog.e(TAG, "Failed to run fstrim!");
567 }
Christopher Tate7265abe2014-11-21 13:54:45 -0800568
Christopher Tated417d622013-08-19 16:14:25 -0700569 // invoke the completion callback, if any
570 Runnable callback = (Runnable) msg.obj;
571 if (callback != null) {
572 callback.run();
573 }
574 break;
575 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700576 case H_SHUTDOWN: {
577 final IMountShutdownObserver obs = (IMountShutdownObserver) msg.obj;
578 boolean success = false;
579 try {
580 success = mConnector.execute("volume", "shutdown").isClassOk();
581 } catch (NativeDaemonConnectorException ignored) {
582 }
583 if (obs != null) {
584 try {
585 obs.onShutDownComplete(success ? 0 : -1);
586 } catch (RemoteException ignored) {
587 }
588 }
589 break;
590 }
591 case H_VOLUME_MOUNT: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700592 final VolumeInfo vol = (VolumeInfo) msg.obj;
Jeff Sharkey48877892015-03-18 11:27:19 -0700593 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700594 mConnector.execute("volume", "mount", vol.id, vol.mountFlags,
595 vol.mountUserId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700596 } catch (NativeDaemonConnectorException ignored) {
597 }
598 break;
599 }
600 case H_VOLUME_BROADCAST: {
601 final StorageVolume userVol = (StorageVolume) msg.obj;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700602 final String envState = userVol.getState();
603 Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + envState + " to "
Jeff Sharkey48877892015-03-18 11:27:19 -0700604 + userVol.getOwner());
605
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700606 final String action = VolumeInfo.getBroadcastForEnvironment(envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700607 if (action != null) {
608 final Intent intent = new Intent(action,
609 Uri.fromFile(userVol.getPathFile()));
610 intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, userVol);
611 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
612 mContext.sendBroadcastAsUser(intent, userVol.getOwner());
613 }
614 break;
615 }
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800616 }
617 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700618 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700619
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700620 private final Handler mHandler;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800621
Jeff Sharkey56e62932015-03-21 20:41:00 -0700622 @Override
623 public void waitForAsecScan() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700624 waitForLatch(mAsecsScanned, "mAsecsScanned");
Kenny Root51a573c2012-05-17 13:30:28 -0700625 }
626
San Mehat207e5382010-02-04 20:46:54 -0800627 private void waitForReady() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700628 waitForLatch(mConnectedSignal, "mConnectedSignal");
Kenny Root51a573c2012-05-17 13:30:28 -0700629 }
630
Jeff Sharkey48877892015-03-18 11:27:19 -0700631 private void waitForLatch(CountDownLatch latch, String condition) {
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700632 while (true) {
Kenny Root51a573c2012-05-17 13:30:28 -0700633 try {
634 if (latch.await(5000, TimeUnit.MILLISECONDS)) {
San Mehat207e5382010-02-04 20:46:54 -0800635 return;
Kenny Root51a573c2012-05-17 13:30:28 -0700636 } else {
637 Slog.w(TAG, "Thread " + Thread.currentThread().getName()
Jeff Sharkey48877892015-03-18 11:27:19 -0700638 + " still waiting for " + condition + "...");
San Mehat207e5382010-02-04 20:46:54 -0800639 }
Kenny Root51a573c2012-05-17 13:30:28 -0700640 } catch (InterruptedException e) {
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700641 Slog.w(TAG, "Interrupt while waiting for " + condition);
San Mehat207e5382010-02-04 20:46:54 -0800642 }
San Mehat207e5382010-02-04 20:46:54 -0800643 }
San Mehat1f6301e2010-01-07 22:40:27 -0800644 }
Kenny Root02c87302010-07-01 08:10:18 -0700645
Paul Lawrence945490c2014-03-27 16:37:28 +0000646 private boolean isReady() {
647 try {
648 return mConnectedSignal.await(0, TimeUnit.MILLISECONDS);
649 } catch (InterruptedException e) {
650 return false;
651 }
652 }
653
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700654 private void handleSystemReady() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700655 resetIfReadyAndConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700656
Jeff Sharkey48877892015-03-18 11:27:19 -0700657 // Start scheduling nominally-daily fstrim operations
Christopher Tate115afda2014-06-06 19:06:26 -0700658 MountServiceIdler.scheduleIdlePass(mContext);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700659 }
660
Jeff Sharkey48877892015-03-18 11:27:19 -0700661 private void resetIfReadyAndConnected() {
662 Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
663 + ", mDaemonConnected=" + mDaemonConnected);
664 if (mSystemReady && mDaemonConnected) {
665 mDisks.clear();
666 mVolumes.clear();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700667
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700668 // Create a stub volume that represents internal storage
669 final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700670 VolumeInfo.TYPE_PRIVATE, null, 0);
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700671 internal.state = VolumeInfo.STATE_MOUNTED;
672 internal.path = Environment.getDataDirectory().getAbsolutePath();
673 mVolumes.put(internal.id, internal);
674
Jeff Sharkey48877892015-03-18 11:27:19 -0700675 try {
676 mConnector.execute("volume", "reset");
Jeff Sharkey50a05452015-04-29 11:24:52 -0700677 for (int userId : mStartedUsers) {
678 mConnector.execute("volume", "start_user", userId);
679 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700680 } catch (NativeDaemonConnectorException e) {
681 Slog.w(TAG, "Failed to reset vold", e);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700682 }
683 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700684 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700685
Jeff Sharkey48877892015-03-18 11:27:19 -0700686 private void onStartUser(int userId) {
687 Slog.d(TAG, "onStartUser " + userId);
688
689 // We purposefully block here to make sure that user-specific
690 // staging area is ready so it's ready for zygote-forked apps to
691 // bind mount against.
692 try {
693 mConnector.execute("volume", "start_user", userId);
694 } catch (NativeDaemonConnectorException ignored) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700695 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700696
697 // Record user as started so newly mounted volumes kick off events
698 // correctly, then synthesize events for any already-mounted volumes.
699 synchronized (mVolumes) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700700 for (int i = 0; i < mVolumes.size(); i++) {
701 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700702 if (vol.isVisibleToUser(userId) && vol.isMountedReadable()) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700703 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700704 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700705
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700706 final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
707 mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700708 }
709 }
710 mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userId);
711 }
712 }
713
714 private void onCleanupUser(int userId) {
715 Slog.d(TAG, "onCleanupUser " + userId);
716
717 try {
718 mConnector.execute("volume", "cleanup_user", userId);
719 } catch (NativeDaemonConnectorException ignored) {
720 }
721
722 synchronized (mVolumes) {
723 mStartedUsers = ArrayUtils.removeInt(mStartedUsers, userId);
724 }
725 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700726
Christopher Tated417d622013-08-19 16:14:25 -0700727 void runIdleMaintenance(Runnable callback) {
728 mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
729 }
730
Christopher Tate7265abe2014-11-21 13:54:45 -0800731 // Binder entry point for kicking off an immediate fstrim
732 @Override
733 public void runMaintenance() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700734 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Christopher Tate7265abe2014-11-21 13:54:45 -0800735 runIdleMaintenance(null);
736 }
737
738 @Override
739 public long lastMaintenance() {
740 return mLastMaintenance;
741 }
742
San Mehat4270e1e2010-01-29 05:32:19 -0800743 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800744 * Callback from NativeDaemonConnector
745 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700746 @Override
San Mehat4270e1e2010-01-29 05:32:19 -0800747 public void onDaemonConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700748 mDaemonConnected = true;
749 mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();
750 }
751
752 private void handleDaemonConnected() {
753 resetIfReadyAndConnected();
754
San Mehat4270e1e2010-01-29 05:32:19 -0800755 /*
Jeff Sharkey48877892015-03-18 11:27:19 -0700756 * Now that we've done our initialization, release
757 * the hounds!
San Mehat4270e1e2010-01-29 05:32:19 -0800758 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700759 mConnectedSignal.countDown();
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700760 if (mConnectedSignal.getCount() != 0) {
761 // More daemons need to connect
762 return;
763 }
Mike Lockwood7fa24aa2011-03-23 14:52:34 -0400764
Jeff Sharkey48877892015-03-18 11:27:19 -0700765 // On an encrypted device we can't see system properties yet, so pull
766 // the system locale out of the mount service.
767 if ("".equals(SystemProperties.get("vold.encrypt_progress"))) {
768 copyLocaleFromMountService();
769 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700770
Jeff Sharkey48877892015-03-18 11:27:19 -0700771 // Let package manager load internal ASECs.
772 mPms.scanAvailableAsecs();
Mike Lockwood7fa24aa2011-03-23 14:52:34 -0400773
Jeff Sharkey48877892015-03-18 11:27:19 -0700774 // Notify people waiting for ASECs to be scanned that it's done.
775 mAsecsScanned.countDown();
San Mehat4270e1e2010-01-29 05:32:19 -0800776 }
777
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700778 private void copyLocaleFromMountService() {
779 String systemLocale;
780 try {
781 systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
782 } catch (RemoteException e) {
783 return;
784 }
785 if (TextUtils.isEmpty(systemLocale)) {
786 return;
787 }
788
789 Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
790 Locale locale = Locale.forLanguageTag(systemLocale);
791 Configuration config = new Configuration();
792 config.setLocale(locale);
793 try {
794 ActivityManagerNative.getDefault().updateConfiguration(config);
795 } catch (RemoteException e) {
796 Slog.e(TAG, "Error setting system locale from mount service", e);
797 }
Elliott Hughes9c33f282014-10-13 12:39:56 -0700798
799 // Temporary workaround for http://b/17945169.
800 Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
Narayan Kamathd30dbb82015-01-15 14:48:15 +0000801 SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700802 }
803
San Mehat4270e1e2010-01-29 05:32:19 -0800804 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800805 * Callback from NativeDaemonConnector
806 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700807 @Override
Dianne Hackborn77b987f2014-02-26 16:20:52 -0800808 public boolean onCheckHoldWakeLock(int code) {
809 return false;
810 }
811
812 /**
813 * Callback from NativeDaemonConnector
814 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700815 @Override
San Mehat4270e1e2010-01-29 05:32:19 -0800816 public boolean onEvent(int code, String raw, String[] cooked) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700817 synchronized (mLock) {
818 return onEventLocked(code, raw, cooked);
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -0800819 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700820 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -0700821
Jeff Sharkey48877892015-03-18 11:27:19 -0700822 private boolean onEventLocked(int code, String raw, String[] cooked) {
823 switch (code) {
824 case VoldResponseCode.DISK_CREATED: {
825 if (cooked.length != 3) break;
826 final String id = cooked[1];
Jeff Sharkey74acbbb2015-04-21 12:14:03 -0700827 int flags = Integer.parseInt(cooked[2]);
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700828 if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false)
829 || mForceAdoptable) {
Jeff Sharkey74acbbb2015-04-21 12:14:03 -0700830 flags |= DiskInfo.FLAG_ADOPTABLE;
831 }
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700832 mDisks.put(id, new DiskInfo(id, flags));
Jeff Sharkey48877892015-03-18 11:27:19 -0700833 break;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -0700834 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700835 case VoldResponseCode.DISK_SIZE_CHANGED: {
836 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700837 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -0700838 if (disk != null) {
839 disk.size = Long.parseLong(cooked[2]);
San Mehat4270e1e2010-01-29 05:32:19 -0800840 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700841 break;
842 }
843 case VoldResponseCode.DISK_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700844 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -0700845 if (disk != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700846 final StringBuilder builder = new StringBuilder();
847 for (int i = 2; i < cooked.length; i++) {
848 builder.append(cooked[i]).append(' ');
849 }
850 disk.label = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -0700851 }
852 break;
853 }
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700854 case VoldResponseCode.DISK_SCANNED: {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700855 if (cooked.length != 2) break;
856 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700857 if (disk != null) {
858 onDiskScannedLocked(disk);
859 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700860 break;
861 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700862 case VoldResponseCode.DISK_DESTROYED: {
863 if (cooked.length != 2) break;
864 mDisks.remove(cooked[1]);
865 break;
866 }
San Mehat4270e1e2010-01-29 05:32:19 -0800867
Jeff Sharkey48877892015-03-18 11:27:19 -0700868 case VoldResponseCode.VOLUME_CREATED: {
Jeff Sharkey48877892015-03-18 11:27:19 -0700869 final String id = cooked[1];
870 final int type = Integer.parseInt(cooked[2]);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700871 final String diskId = (cooked.length == 4) ? cooked[3] : null;
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700872 final DiskInfo disk = mDisks.get(diskId);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700873 final int mtpIndex = allocateMtpIndex(id);
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700874 final VolumeInfo vol = new VolumeInfo(id, type, disk, mtpIndex);
Jeff Sharkey48877892015-03-18 11:27:19 -0700875 mVolumes.put(id, vol);
876 onVolumeCreatedLocked(vol);
877 break;
878 }
879 case VoldResponseCode.VOLUME_STATE_CHANGED: {
880 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700881 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -0700882 if (vol != null) {
883 final int oldState = vol.state;
884 final int newState = Integer.parseInt(cooked[2]);
885 vol.state = newState;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700886 onVolumeStateChangedLocked(vol, oldState, newState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700887 }
888 break;
889 }
890 case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: {
891 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700892 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -0700893 if (vol != null) {
894 vol.fsType = cooked[2];
895 }
896 break;
897 }
898 case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
899 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700900 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -0700901 if (vol != null) {
902 vol.fsUuid = cooked[2];
903 }
904 break;
905 }
906 case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700907 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -0700908 if (vol != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700909 final StringBuilder builder = new StringBuilder();
910 for (int i = 2; i < cooked.length; i++) {
911 builder.append(cooked[i]).append(' ');
912 }
913 vol.fsLabel = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -0700914 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700915 // TODO: notify listeners that label changed
Jeff Sharkey48877892015-03-18 11:27:19 -0700916 break;
917 }
918 case VoldResponseCode.VOLUME_PATH_CHANGED: {
919 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700920 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -0700921 if (vol != null) {
922 vol.path = cooked[2];
923 }
924 break;
925 }
Jeff Sharkey50a05452015-04-29 11:24:52 -0700926 case VoldResponseCode.VOLUME_INTERNAL_PATH_CHANGED: {
927 if (cooked.length != 3) break;
928 final VolumeInfo vol = mVolumes.get(cooked[1]);
929 if (vol != null) {
930 vol.internalPath = cooked[2];
931 }
932 break;
933 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700934 case VoldResponseCode.VOLUME_DESTROYED: {
935 if (cooked.length != 2) break;
936 mVolumes.remove(cooked[1]);
937 break;
938 }
San Mehat4270e1e2010-01-29 05:32:19 -0800939
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700940 case VoldResponseCode.MOVE_STATUS: {
941 final int status = Integer.parseInt(cooked[1]);
942 onMoveStatusLocked(status);
943 break;
944 }
945
Jeff Sharkey9756d752015-05-14 21:07:42 -0700946 case VoldResponseCode.BENCHMARK_RESULT: {
947 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
948 dropBox.addText(TAG_STORAGE_BENCHMARK, raw);
949 break;
950 }
951
Jeff Sharkey48877892015-03-18 11:27:19 -0700952 case VoldResponseCode.FstrimCompleted: {
Svetoslav9e814a82013-04-30 10:43:56 -0700953 EventLogTags.writeFstrimFinish(SystemClock.elapsedRealtime());
Jeff Sharkey48877892015-03-18 11:27:19 -0700954 break;
San Mehat4270e1e2010-01-29 05:32:19 -0800955 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700956 default: {
957 Slog.d(TAG, "Unhandled vold event " + code);
Mike Lockwooda5250c92011-05-23 13:44:04 -0400958 }
San Mehat4270e1e2010-01-29 05:32:19 -0800959 }
960
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400961 return true;
San Mehat4270e1e2010-01-29 05:32:19 -0800962 }
963
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700964 private void onDiskScannedLocked(DiskInfo disk) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700965 final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
966 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
967 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
968 android.Manifest.permission.WRITE_MEDIA_STORAGE);
969
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700970 final CountDownLatch latch = mDiskScanLatches.remove(disk.id);
971 if (latch != null) {
972 latch.countDown();
973 }
974
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700975 int volumeCount = 0;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700976 for (int i = 0; i < mVolumes.size(); i++) {
977 final VolumeInfo vol = mVolumes.valueAt(i);
978 if (Objects.equals(disk.id, vol.getDiskId())) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700979 volumeCount++;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700980 }
981 }
982
Jeff Sharkeyf5a6bd72015-05-19 14:42:38 -0700983 disk.volumeCount = volumeCount;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700984 mCallbacks.notifyDiskScanned(disk, volumeCount);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700985 }
986
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700987 private void onVolumeCreatedLocked(VolumeInfo vol) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700988 if (vol.type == VolumeInfo.TYPE_EMULATED) {
989 final StorageManager storage = mContext.getSystemService(StorageManager.class);
990 final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
991
992 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
993 && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
994 Slog.v(TAG, "Found primary storage at " + vol);
995 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
996 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
997 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
998
999 } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
1000 Slog.v(TAG, "Found primary storage at " + vol);
1001 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1002 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1003 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1004 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001005
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001006 } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001007 // TODO: only look at first public partition
1008 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1009 && vol.disk.isDefaultPrimary()) {
1010 Slog.v(TAG, "Found primary storage at " + vol);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001011 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1012 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
San Mehat4270e1e2010-01-29 05:32:19 -08001013 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001014
1015 // Adoptable public disks are visible to apps, since they meet
1016 // public API requirement of being in a stable location.
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001017 if (vol.disk.isAdoptable()) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001018 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1019 }
1020
1021 vol.mountUserId = UserHandle.USER_OWNER;
Jeff Sharkey48877892015-03-18 11:27:19 -07001022 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001023
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001024 } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1025 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1026
San Mehat4270e1e2010-01-29 05:32:19 -08001027 } else {
Jeff Sharkey48877892015-03-18 11:27:19 -07001028 Slog.d(TAG, "Skipping automatic mounting of " + vol);
San Mehat4270e1e2010-01-29 05:32:19 -08001029 }
1030 }
1031
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001032 private boolean isBroadcastWorthy(VolumeInfo vol) {
1033 switch (vol.getType()) {
1034 case VolumeInfo.TYPE_PUBLIC:
1035 case VolumeInfo.TYPE_EMULATED:
1036 break;
1037 default:
1038 return false;
1039 }
1040
1041 switch (vol.getState()) {
1042 case VolumeInfo.STATE_MOUNTED:
1043 case VolumeInfo.STATE_MOUNTED_READ_ONLY:
1044 case VolumeInfo.STATE_EJECTING:
1045 case VolumeInfo.STATE_UNMOUNTED:
1046 break;
1047 default:
1048 return false;
1049 }
1050
1051 return true;
1052 }
1053
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001054 private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001055 // Remember that we saw this volume so we're ready to accept user
1056 // metadata, or so we can annoy them when a private volume is ejected
1057 if (vol.isMountedReadable() && !TextUtils.isEmpty(vol.fsUuid)) {
1058 if (!mRecords.containsKey(vol.fsUuid)) {
1059 final VolumeRecord rec = new VolumeRecord(vol.type, vol.fsUuid);
1060 if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1061 rec.nickname = vol.disk.getDescription();
1062 }
1063 mRecords.put(rec.fsUuid, rec);
1064 writeSettingsLocked();
1065 }
1066 }
1067
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001068 mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
1069
1070 if (isBroadcastWorthy(vol)) {
1071 final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
1072 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001073 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
1074 android.Manifest.permission.WRITE_MEDIA_STORAGE);
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001075 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001076
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001077 final String oldStateEnv = VolumeInfo.getEnvironmentForState(oldState);
1078 final String newStateEnv = VolumeInfo.getEnvironmentForState(newState);
Emily Bernier92aa5a22014-07-07 10:11:48 -04001079
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001080 if (!Objects.equals(oldStateEnv, newStateEnv)) {
1081 // Kick state changed event towards all started users. Any users
1082 // started after this point will trigger additional
1083 // user-specific broadcasts.
1084 for (int userId : mStartedUsers) {
1085 if (vol.isVisibleToUser(userId)) {
1086 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
1087 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey48877892015-03-18 11:27:19 -07001088
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001089 mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
1090 newStateEnv);
San Mehat4270e1e2010-01-29 05:32:19 -08001091 }
1092 }
1093 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001094
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001095 if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.state == VolumeInfo.STATE_EJECTING) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001096 // TODO: this should eventually be handled by new ObbVolume state changes
1097 /*
1098 * Some OBBs might have been unmounted when this volume was
1099 * unmounted, so send a message to the handler to let it know to
1100 * remove those from the list of mounted OBBS.
1101 */
1102 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
1103 OBB_FLUSH_MOUNT_STATE, vol.path));
1104 }
San Mehat4270e1e2010-01-29 05:32:19 -08001105 }
1106
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001107 private void onMoveStatusLocked(int status) {
1108 if (mMoveCallback == null) {
1109 Slog.w(TAG, "Odd, status but no move requested");
1110 return;
1111 }
1112
1113 // TODO: estimate remaining time
1114 try {
Jeff Sharkey50a05452015-04-29 11:24:52 -07001115 mMoveCallback.onStatusChanged(-1, status, -1);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001116 } catch (RemoteException ignored) {
1117 }
1118
1119 // We've finished copying and we're about to clean up old data, so
1120 // remember that move was successful if we get rebooted
1121 if (status == MOVE_STATUS_COPY_FINISHED) {
1122 Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
1123
1124 mPrimaryStorageUuid = mMoveTargetUuid;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001125 writeSettingsLocked();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001126 }
1127
1128 if (PackageManager.isMoveStatusFinished(status)) {
1129 Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status);
1130
1131 mMoveCallback = null;
1132 mMoveTargetUuid = null;
1133 }
1134 }
1135
Jeff Sharkey48877892015-03-18 11:27:19 -07001136 private void enforcePermission(String perm) {
1137 mContext.enforceCallingOrSelfPermission(perm, perm);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001138 }
1139
Jeff Sharkey48877892015-03-18 11:27:19 -07001140 private void enforceUserRestriction(String restriction) {
Emily Bernier92aa5a22014-07-07 10:11:48 -04001141 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
Jeff Sharkey48877892015-03-18 11:27:19 -07001142 if (um.hasUserRestriction(restriction, Binder.getCallingUserHandle())) {
Emily Bernier92aa5a22014-07-07 10:11:48 -04001143 throw new SecurityException("User has restriction " + restriction);
1144 }
1145 }
1146
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001147 /**
San Mehat207e5382010-02-04 20:46:54 -08001148 * Constructs a new MountService instance
1149 *
1150 * @param context Binder context for this service
1151 */
1152 public MountService(Context context) {
Christopher Tated417d622013-08-19 16:14:25 -07001153 sSelf = this;
1154
San Mehat207e5382010-02-04 20:46:54 -08001155 mContext = context;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001156 mCallbacks = new Callbacks(FgThread.get().getLooper());
San Mehat207e5382010-02-04 20:46:54 -08001157
San Mehat207e5382010-02-04 20:46:54 -08001158 // XXX: This will go away soon in favor of IMountServiceObserver
1159 mPms = (PackageManagerService) ServiceManager.getService("package");
1160
Dianne Hackbornefa92b22013-05-03 14:11:43 -07001161 HandlerThread hthread = new HandlerThread(TAG);
1162 hthread.start();
1163 mHandler = new MountServiceHandler(hthread.getLooper());
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001164
Kenny Roota02b8b02010-08-05 16:14:17 -07001165 // Add OBB Action Handler to MountService thread.
Dianne Hackborn8d044e82013-04-30 17:24:15 -07001166 mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
Kenny Roota02b8b02010-08-05 16:14:17 -07001167
Christopher Tate7265abe2014-11-21 13:54:45 -08001168 // Initialize the last-fstrim tracking if necessary
1169 File dataDir = Environment.getDataDirectory();
1170 File systemDir = new File(dataDir, "system");
1171 mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
1172 if (!mLastMaintenanceFile.exists()) {
1173 // Not setting mLastMaintenance here means that we will force an
1174 // fstrim during reboot following the OTA that installs this code.
1175 try {
1176 (new FileOutputStream(mLastMaintenanceFile)).close();
1177 } catch (IOException e) {
1178 Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
1179 }
1180 } else {
1181 mLastMaintenance = mLastMaintenanceFile.lastModified();
1182 }
1183
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001184 mSettingsFile = new AtomicFile(
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001185 new File(Environment.getSystemSecureDirectory(), "storage.xml"));
1186
1187 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001188 readSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001189 }
1190
Marco Nelissenc34ebce2010-02-18 13:39:41 -08001191 /*
Kenny Root305bcbf2010-09-03 07:56:38 -07001192 * Create the connection to vold with a maximum queue of twice the
1193 * amount of containers we'd ever expect to have. This keeps an
1194 * "asec list" from blocking a thread repeatedly.
1195 */
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001196
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001197 mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
1198 null);
Jeff Sharkey48877892015-03-18 11:27:19 -07001199 mConnector.setDebug(true);
Kenny Root51a573c2012-05-17 13:30:28 -07001200
Kenny Root305bcbf2010-09-03 07:56:38 -07001201 Thread thread = new Thread(mConnector, VOLD_TAG);
San Mehat207e5382010-02-04 20:46:54 -08001202 thread.start();
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07001203
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001204 // Reuse parameters from first connector since they are tested and safe
1205 mCryptConnector = new NativeDaemonConnector(this, "cryptd",
1206 MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
1207 mCryptConnector.setDebug(true);
1208
1209 Thread crypt_thread = new Thread(mCryptConnector, CRYPTD_TAG);
1210 crypt_thread.start();
1211
Kenny Root07714d42011-08-17 17:49:28 -07001212 // Add ourself to the Watchdog monitors if enabled.
1213 if (WATCHDOG_ENABLE) {
1214 Watchdog.getInstance().addMonitor(this);
1215 }
San Mehat207e5382010-02-04 20:46:54 -08001216 }
1217
Jeff Sharkey56e62932015-03-21 20:41:00 -07001218 private void systemReady() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001219 mSystemReady = true;
1220 mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
1221 }
1222
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001223 private String getDefaultPrimaryStorageUuid() {
1224 if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) {
1225 return StorageManager.UUID_PRIMARY_PHYSICAL;
1226 } else {
1227 return StorageManager.UUID_PRIVATE_INTERNAL;
1228 }
1229 }
1230
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001231 private void readSettingsLocked() {
1232 mRecords.clear();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001233 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001234 mForceAdoptable = false;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001235
1236 FileInputStream fis = null;
1237 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001238 fis = mSettingsFile.openRead();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001239 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001240 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001241
1242 int type;
1243 while ((type = in.next()) != END_DOCUMENT) {
1244 if (type == START_TAG) {
1245 final String tag = in.getName();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001246 if (TAG_VOLUMES.equals(tag)) {
1247 final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001248 final boolean primaryPhysical = SystemProperties.getBoolean(
1249 StorageManager.PROP_PRIMARY_PHYSICAL, false);
1250 final boolean validAttr = (version >= VERSION_FIX_PRIMARY)
1251 || (version >= VERSION_ADD_PRIMARY && !primaryPhysical);
1252 if (validAttr) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001253 mPrimaryStorageUuid = readStringAttribute(in,
1254 ATTR_PRIMARY_STORAGE_UUID);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001255 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001256 mForceAdoptable = readBooleanAttribute(in, ATTR_FORCE_ADOPTABLE, false);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001257
1258 } else if (TAG_VOLUME.equals(tag)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001259 final VolumeRecord rec = readVolumeRecord(in);
1260 mRecords.put(rec.fsUuid, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001261 }
1262 }
1263 }
1264 } catch (FileNotFoundException e) {
1265 // Missing metadata is okay, probably first boot
1266 } catch (IOException e) {
1267 Slog.wtf(TAG, "Failed reading metadata", e);
1268 } catch (XmlPullParserException e) {
1269 Slog.wtf(TAG, "Failed reading metadata", e);
1270 } finally {
1271 IoUtils.closeQuietly(fis);
1272 }
1273 }
1274
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001275 private void writeSettingsLocked() {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001276 FileOutputStream fos = null;
1277 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001278 fos = mSettingsFile.startWrite();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001279
1280 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001281 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001282 out.startDocument(null, true);
1283 out.startTag(null, TAG_VOLUMES);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001284 writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001285 writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001286 writeBooleanAttribute(out, ATTR_FORCE_ADOPTABLE, mForceAdoptable);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001287 final int size = mRecords.size();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001288 for (int i = 0; i < size; i++) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001289 final VolumeRecord rec = mRecords.valueAt(i);
1290 writeVolumeRecord(out, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001291 }
1292 out.endTag(null, TAG_VOLUMES);
1293 out.endDocument();
1294
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001295 mSettingsFile.finishWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001296 } catch (IOException e) {
1297 if (fos != null) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001298 mSettingsFile.failWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001299 }
1300 }
1301 }
1302
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001303 public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
1304 final int type = readIntAttribute(in, ATTR_TYPE);
1305 final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
1306 final VolumeRecord meta = new VolumeRecord(type, fsUuid);
1307 meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
1308 meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
1309 return meta;
1310 }
1311
1312 public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
1313 out.startTag(null, TAG_VOLUME);
1314 writeIntAttribute(out, ATTR_TYPE, rec.type);
1315 writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
1316 writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
1317 writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
1318 out.endTag(null, TAG_VOLUME);
1319 }
1320
San Mehat207e5382010-02-04 20:46:54 -08001321 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001322 * Exposed API calls below here
1323 */
1324
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001325 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001326 public void registerListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001327 mCallbacks.register(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001328 }
1329
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001330 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001331 public void unregisterListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001332 mCallbacks.unregister(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001333 }
1334
Jeff Sharkey48877892015-03-18 11:27:19 -07001335 @Override
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -08001336 public void shutdown(final IMountShutdownObserver observer) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001337 enforcePermission(android.Manifest.permission.SHUTDOWN);
San Mehat4270e1e2010-01-29 05:32:19 -08001338
San Mehata5078592010-03-25 09:36:54 -07001339 Slog.i(TAG, "Shutting down");
Jeff Sharkey48877892015-03-18 11:27:19 -07001340 mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001341 }
1342
Jeff Sharkey48877892015-03-18 11:27:19 -07001343 @Override
San Mehatb1043402010-02-05 08:26:50 -08001344 public boolean isUsbMassStorageConnected() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001345 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001346 }
1347
Jeff Sharkey48877892015-03-18 11:27:19 -07001348 @Override
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -08001349 public void setUsbMassStorageEnabled(boolean enable) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001350 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001351 }
1352
Jeff Sharkey48877892015-03-18 11:27:19 -07001353 @Override
San Mehatb1043402010-02-05 08:26:50 -08001354 public boolean isUsbMassStorageEnabled() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001355 throw new UnsupportedOperationException();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001356 }
Jason parks9ed98bc2011-01-17 09:58:35 -06001357
Jeff Sharkey48877892015-03-18 11:27:19 -07001358 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001359 public String getVolumeState(String mountPoint) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001360 throw new UnsupportedOperationException();
San Mehat7fd0fee2009-12-17 07:12:23 -08001361 }
1362
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001363 @Override
Kenny Roote1ff2142010-10-12 11:20:01 -07001364 public boolean isExternalStorageEmulated() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001365 throw new UnsupportedOperationException();
Kenny Roote1ff2142010-10-12 11:20:01 -07001366 }
1367
Jeff Sharkey48877892015-03-18 11:27:19 -07001368 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001369 public int mountVolume(String path) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001370 mount(findVolumeIdForPath(path));
1371 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372 }
1373
Jeff Sharkey48877892015-03-18 11:27:19 -07001374 @Override
Ben Komalo13c71972011-09-07 16:35:56 -07001375 public void unmountVolume(String path, boolean force, boolean removeEncryption) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001376 unmount(findVolumeIdForPath(path));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 }
1378
Jeff Sharkey48877892015-03-18 11:27:19 -07001379 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001380 public int formatVolume(String path) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001381 format(findVolumeIdForPath(path));
1382 return 0;
1383 }
1384
1385 @Override
1386 public void mount(String volId) {
1387 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1388 waitForReady();
1389
1390 final VolumeInfo vol = findVolumeById(volId);
1391 if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
1392 enforceUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA);
1393 }
1394 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001395 mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001396 } catch (NativeDaemonConnectorException e) {
1397 throw e.rethrowAsParcelableException();
1398 }
1399 }
1400
1401 @Override
1402 public void unmount(String volId) {
1403 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1404 waitForReady();
1405
1406 final VolumeInfo vol = findVolumeById(volId);
1407
1408 // TODO: expand PMS to know about multiple volumes
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001409 if (vol.isPrimaryPhysical()) {
1410 final long ident = Binder.clearCallingIdentity();
1411 try {
1412 synchronized (mUnmountLock) {
1413 mUnmountSignal = new CountDownLatch(1);
1414 mPms.updateExternalMediaStatus(false, true);
1415 waitForLatch(mUnmountSignal, "mUnmountSignal");
1416 mUnmountSignal = null;
1417 }
1418 } finally {
1419 Binder.restoreCallingIdentity(ident);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001420 }
1421 }
1422
1423 try {
1424 mConnector.execute("volume", "unmount", vol.id);
1425 } catch (NativeDaemonConnectorException e) {
1426 throw e.rethrowAsParcelableException();
1427 }
1428 }
1429
1430 @Override
1431 public void format(String volId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001432 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -08001433 waitForReady();
San Mehat5b77dab2010-01-26 13:28:50 -08001434
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001435 final VolumeInfo vol = findVolumeById(volId);
1436 try {
1437 mConnector.execute("volume", "format", vol.id);
1438 } catch (NativeDaemonConnectorException e) {
1439 throw e.rethrowAsParcelableException();
Jeff Sharkey48877892015-03-18 11:27:19 -07001440 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001441 }
1442
1443 @Override
Jeff Sharkey9756d752015-05-14 21:07:42 -07001444 public long benchmark(String volId) {
1445 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1446 waitForReady();
1447
1448 try {
1449 final NativeDaemonEvent res = mConnector.execute("volume", "benchmark", volId);
1450 return Long.parseLong(res.getMessage());
1451 } catch (NativeDaemonConnectorException e) {
1452 throw e.rethrowAsParcelableException();
1453 }
1454 }
1455
1456 @Override
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001457 public void partitionPublic(String diskId) {
1458 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1459 waitForReady();
1460
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001461 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001462 try {
1463 mConnector.execute("volume", "partition", diskId, "public");
1464 } catch (NativeDaemonConnectorException e) {
1465 throw e.rethrowAsParcelableException();
1466 }
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001467 waitForLatch(latch, "partitionPublic");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001468 }
1469
1470 @Override
1471 public void partitionPrivate(String diskId) {
1472 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1473 waitForReady();
1474
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001475 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001476 try {
1477 mConnector.execute("volume", "partition", diskId, "private");
1478 } catch (NativeDaemonConnectorException e) {
1479 throw e.rethrowAsParcelableException();
1480 }
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001481 waitForLatch(latch, "partitionPrivate");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001482 }
1483
1484 @Override
1485 public void partitionMixed(String diskId, int ratio) {
1486 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1487 waitForReady();
1488
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001489 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001490 try {
1491 mConnector.execute("volume", "partition", diskId, "mixed", ratio);
1492 } catch (NativeDaemonConnectorException e) {
1493 throw e.rethrowAsParcelableException();
1494 }
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001495 waitForLatch(latch, "partitionMixed");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001496 }
1497
Jeff Sharkey48877892015-03-18 11:27:19 -07001498 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001499 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001500 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1501 waitForReady();
1502
Jeff Sharkey50a05452015-04-29 11:24:52 -07001503 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001504 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001505 final VolumeRecord rec = mRecords.get(fsUuid);
1506 rec.nickname = nickname;
Jeff Sharkey50a05452015-04-29 11:24:52 -07001507 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001508 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001509 }
1510 }
1511
1512 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001513 public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001514 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1515 waitForReady();
1516
Jeff Sharkey50a05452015-04-29 11:24:52 -07001517 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001518 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001519 final VolumeRecord rec = mRecords.get(fsUuid);
1520 rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001521 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001522 writeSettingsLocked();
1523 }
1524 }
1525
1526 @Override
1527 public void forgetVolume(String fsUuid) {
1528 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1529 waitForReady();
1530
Jeff Sharkey50a05452015-04-29 11:24:52 -07001531 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001532 synchronized (mLock) {
1533 mRecords.remove(fsUuid);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001534
1535 // TODO: tell vold to forget keys
1536
1537 // If this had been primary storage, revert back to internal and
1538 // reset vold so we bind into new volume into place.
1539 if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001540 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001541 resetIfReadyAndConnected();
1542 }
1543
1544 mCallbacks.notifyVolumeForgotten(fsUuid);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001545 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001546 }
1547 }
1548
Jeff Sharkey7d2af542015-05-12 15:27:15 -07001549 @Override
1550 public void forgetAllVolumes() {
1551 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1552 waitForReady();
1553
Jeff Sharkey50a05452015-04-29 11:24:52 -07001554 synchronized (mLock) {
1555 for (int i = 0; i < mRecords.size(); i++) {
1556 final String fsUuid = mRecords.keyAt(i);
1557 mCallbacks.notifyVolumeForgotten(fsUuid);
1558 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001559 mRecords.clear();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001560
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001561 if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)) {
1562 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
1563 }
1564
1565 writeSettingsLocked();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001566 resetIfReadyAndConnected();
1567 }
1568 }
1569
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001570 @Override
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001571 public void setDebugFlags(int flags, int mask) {
1572 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1573 waitForReady();
1574
1575 synchronized (mLock) {
1576 if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
1577 mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
1578 }
1579
1580 writeSettingsLocked();
1581 resetIfReadyAndConnected();
1582 }
1583 }
1584
1585 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001586 public String getPrimaryStorageUuid() {
1587 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1588 waitForReady();
1589
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001590 synchronized (mLock) {
1591 return mPrimaryStorageUuid;
1592 }
1593 }
1594
1595 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001596 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
1597 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1598 waitForReady();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001599
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001600 synchronized (mLock) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001601 if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) {
1602 throw new IllegalArgumentException("Primary storage already at " + volumeUuid);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001603 }
1604
1605 if (mMoveCallback != null) {
1606 throw new IllegalStateException("Move already in progress");
1607 }
1608 mMoveCallback = callback;
1609 mMoveTargetUuid = volumeUuid;
1610
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001611 // When moving to/from primary physical volume, we probably just nuked
1612 // the current storage location, so we have nothing to move.
1613 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1614 || Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
1615 Slog.d(TAG, "Skipping move to/from primary physical");
1616 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
1617 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
1618 resetIfReadyAndConnected();
1619
1620 } else {
1621 final VolumeInfo from = Preconditions.checkNotNull(
1622 findStorageForUuid(mPrimaryStorageUuid));
1623 final VolumeInfo to = Preconditions.checkNotNull(
1624 findStorageForUuid(volumeUuid));
1625
1626 try {
1627 mConnector.execute("volume", "move_storage", from.id, to.id);
1628 } catch (NativeDaemonConnectorException e) {
1629 throw e.rethrowAsParcelableException();
1630 }
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001631 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001632 }
1633 }
1634
1635 @Override
Mike Lockwoodecedfdc2011-06-08 15:11:59 -07001636 public int[] getStorageUsers(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001637 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehatc1b4ce92010-02-16 17:13:03 -08001638 waitForReady();
1639 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08001640 final String[] r = NativeDaemonEvent.filterMessageList(
1641 mConnector.executeForList("storage", "users", path),
1642 VoldResponseCode.StorageUsersListResult);
1643
San Mehatc1b4ce92010-02-16 17:13:03 -08001644 // FMT: <pid> <process name>
1645 int[] data = new int[r.length];
1646 for (int i = 0; i < r.length; i++) {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08001647 String[] tok = r[i].split(" ");
San Mehatc1b4ce92010-02-16 17:13:03 -08001648 try {
1649 data[i] = Integer.parseInt(tok[0]);
1650 } catch (NumberFormatException nfe) {
San Mehata5078592010-03-25 09:36:54 -07001651 Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
San Mehatc1b4ce92010-02-16 17:13:03 -08001652 return new int[0];
1653 }
1654 }
1655 return data;
1656 } catch (NativeDaemonConnectorException e) {
San Mehata5078592010-03-25 09:36:54 -07001657 Slog.e(TAG, "Failed to retrieve storage users list", e);
San Mehatc1b4ce92010-02-16 17:13:03 -08001658 return new int[0];
1659 }
1660 }
1661
San Mehatb1043402010-02-05 08:26:50 -08001662 private void warnOnNotMounted() {
Jeff Sharkey48877892015-03-18 11:27:19 -07001663 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001664 for (int i = 0; i < mVolumes.size(); i++) {
1665 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001666 if (vol.isPrimary() && vol.isMountedWritable()) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001667 // Cool beans, we have a mounted primary volume
1668 return;
1669 }
Jeff Sharkey32ee8312012-09-30 13:21:31 -07001670 }
San Mehatb1043402010-02-05 08:26:50 -08001671 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001672
1673 Slog.w(TAG, "No primary storage mounted!");
San Mehatb1043402010-02-05 08:26:50 -08001674 }
1675
San Mehat4270e1e2010-01-29 05:32:19 -08001676 public String[] getSecureContainerList() {
Jeff Sharkey48877892015-03-18 11:27:19 -07001677 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08001678 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08001679 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08001680
San Mehat4270e1e2010-01-29 05:32:19 -08001681 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08001682 return NativeDaemonEvent.filterMessageList(
1683 mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
San Mehat4270e1e2010-01-29 05:32:19 -08001684 } catch (NativeDaemonConnectorException e) {
1685 return new String[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001686 }
1687 }
San Mehat36972292010-01-06 11:06:32 -08001688
Kenny Root6dceb882012-04-12 14:23:49 -07001689 public int createSecureContainer(String id, int sizeMb, String fstype, String key,
1690 int ownerUid, boolean external) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001691 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehat207e5382010-02-04 20:46:54 -08001692 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08001693 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08001694
San Mehatb1043402010-02-05 08:26:50 -08001695 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08001696 try {
Jeff Sharkey56cd6462013-06-07 15:09:15 -07001697 mConnector.execute("asec", "create", id, sizeMb, fstype, new SensitiveArg(key),
1698 ownerUid, external ? "1" : "0");
San Mehat4270e1e2010-01-29 05:32:19 -08001699 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08001700 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08001701 }
San Mehata181b212010-02-11 06:50:20 -08001702
1703 if (rc == StorageResultCode.OperationSucceeded) {
1704 synchronized (mAsecMountSet) {
1705 mAsecMountSet.add(id);
1706 }
1707 }
San Mehat4270e1e2010-01-29 05:32:19 -08001708 return rc;
San Mehat36972292010-01-06 11:06:32 -08001709 }
1710
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001711 @Override
1712 public int resizeSecureContainer(String id, int sizeMb, String key) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001713 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001714 waitForReady();
1715 warnOnNotMounted();
1716
1717 int rc = StorageResultCode.OperationSucceeded;
1718 try {
1719 mConnector.execute("asec", "resize", id, sizeMb, new SensitiveArg(key));
1720 } catch (NativeDaemonConnectorException e) {
1721 rc = StorageResultCode.OperationFailedInternalError;
1722 }
1723 return rc;
1724 }
1725
San Mehat4270e1e2010-01-29 05:32:19 -08001726 public int finalizeSecureContainer(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001727 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehatb1043402010-02-05 08:26:50 -08001728 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08001729
San Mehatb1043402010-02-05 08:26:50 -08001730 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08001731 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08001732 mConnector.execute("asec", "finalize", id);
San Mehata181b212010-02-11 06:50:20 -08001733 /*
1734 * Finalization does a remount, so no need
1735 * to update mAsecMountSet
1736 */
San Mehat4270e1e2010-01-29 05:32:19 -08001737 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08001738 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08001739 }
San Mehat4270e1e2010-01-29 05:32:19 -08001740 return rc;
San Mehat36972292010-01-06 11:06:32 -08001741 }
1742
Kenny Root6dceb882012-04-12 14:23:49 -07001743 public int fixPermissionsSecureContainer(String id, int gid, String filename) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001744 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Kenny Root6dceb882012-04-12 14:23:49 -07001745 warnOnNotMounted();
1746
1747 int rc = StorageResultCode.OperationSucceeded;
1748 try {
1749 mConnector.execute("asec", "fixperms", id, gid, filename);
1750 /*
1751 * Fix permissions does a remount, so no need to update
1752 * mAsecMountSet
1753 */
1754 } catch (NativeDaemonConnectorException e) {
1755 rc = StorageResultCode.OperationFailedInternalError;
1756 }
1757 return rc;
1758 }
1759
San Mehatd9709982010-02-18 11:43:03 -08001760 public int destroySecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001761 enforcePermission(android.Manifest.permission.ASEC_DESTROY);
San Mehat207e5382010-02-04 20:46:54 -08001762 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08001763 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08001764
Kenny Rootaa485402010-09-14 14:49:41 -07001765 /*
1766 * Force a GC to make sure AssetManagers in other threads of the
1767 * system_server are cleaned up. We have to do this since AssetManager
1768 * instances are kept as a WeakReference and it's possible we have files
1769 * open on the external storage.
1770 */
1771 Runtime.getRuntime().gc();
1772
San Mehatb1043402010-02-05 08:26:50 -08001773 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08001774 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08001775 final Command cmd = new Command("asec", "destroy", id);
1776 if (force) {
1777 cmd.appendArg("force");
1778 }
1779 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08001780 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08001781 int code = e.getCode();
1782 if (code == VoldResponseCode.OpFailedStorageBusy) {
1783 rc = StorageResultCode.OperationFailedStorageBusy;
1784 } else {
1785 rc = StorageResultCode.OperationFailedInternalError;
1786 }
San Mehat02735bc2010-01-26 15:18:08 -08001787 }
San Mehata181b212010-02-11 06:50:20 -08001788
1789 if (rc == StorageResultCode.OperationSucceeded) {
1790 synchronized (mAsecMountSet) {
1791 if (mAsecMountSet.contains(id)) {
1792 mAsecMountSet.remove(id);
1793 }
1794 }
1795 }
1796
San Mehat4270e1e2010-01-29 05:32:19 -08001797 return rc;
San Mehat36972292010-01-06 11:06:32 -08001798 }
Jason parks9ed98bc2011-01-17 09:58:35 -06001799
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001800 public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001801 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08001802 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08001803 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08001804
San Mehata181b212010-02-11 06:50:20 -08001805 synchronized (mAsecMountSet) {
1806 if (mAsecMountSet.contains(id)) {
1807 return StorageResultCode.OperationFailedStorageMounted;
1808 }
1809 }
1810
San Mehatb1043402010-02-05 08:26:50 -08001811 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08001812 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001813 mConnector.execute("asec", "mount", id, new SensitiveArg(key), ownerUid,
1814 readOnly ? "ro" : "rw");
San Mehat4270e1e2010-01-29 05:32:19 -08001815 } catch (NativeDaemonConnectorException e) {
Kenny Rootf0304622010-03-19 19:20:42 -07001816 int code = e.getCode();
1817 if (code != VoldResponseCode.OpFailedStorageBusy) {
1818 rc = StorageResultCode.OperationFailedInternalError;
1819 }
San Mehat02735bc2010-01-26 15:18:08 -08001820 }
San Mehat6cdd9c02010-02-09 14:45:20 -08001821
1822 if (rc == StorageResultCode.OperationSucceeded) {
1823 synchronized (mAsecMountSet) {
1824 mAsecMountSet.add(id);
1825 }
1826 }
San Mehat4270e1e2010-01-29 05:32:19 -08001827 return rc;
San Mehat36972292010-01-06 11:06:32 -08001828 }
1829
San Mehatd9709982010-02-18 11:43:03 -08001830 public int unmountSecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001831 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08001832 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08001833 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08001834
San Mehat6cdd9c02010-02-09 14:45:20 -08001835 synchronized (mAsecMountSet) {
1836 if (!mAsecMountSet.contains(id)) {
San Mehata181b212010-02-11 06:50:20 -08001837 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehat6cdd9c02010-02-09 14:45:20 -08001838 }
1839 }
1840
Kenny Rootaa485402010-09-14 14:49:41 -07001841 /*
1842 * Force a GC to make sure AssetManagers in other threads of the
1843 * system_server are cleaned up. We have to do this since AssetManager
1844 * instances are kept as a WeakReference and it's possible we have files
1845 * open on the external storage.
1846 */
1847 Runtime.getRuntime().gc();
1848
San Mehatb1043402010-02-05 08:26:50 -08001849 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08001850 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08001851 final Command cmd = new Command("asec", "unmount", id);
1852 if (force) {
1853 cmd.appendArg("force");
1854 }
1855 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08001856 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08001857 int code = e.getCode();
1858 if (code == VoldResponseCode.OpFailedStorageBusy) {
1859 rc = StorageResultCode.OperationFailedStorageBusy;
1860 } else {
1861 rc = StorageResultCode.OperationFailedInternalError;
1862 }
San Mehat02735bc2010-01-26 15:18:08 -08001863 }
San Mehat6cdd9c02010-02-09 14:45:20 -08001864
1865 if (rc == StorageResultCode.OperationSucceeded) {
1866 synchronized (mAsecMountSet) {
1867 mAsecMountSet.remove(id);
1868 }
1869 }
San Mehat4270e1e2010-01-29 05:32:19 -08001870 return rc;
San Mehat9dba7092010-01-18 06:47:41 -08001871 }
1872
San Mehat6cdd9c02010-02-09 14:45:20 -08001873 public boolean isSecureContainerMounted(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001874 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat6cdd9c02010-02-09 14:45:20 -08001875 waitForReady();
1876 warnOnNotMounted();
1877
1878 synchronized (mAsecMountSet) {
1879 return mAsecMountSet.contains(id);
1880 }
1881 }
1882
San Mehat4270e1e2010-01-29 05:32:19 -08001883 public int renameSecureContainer(String oldId, String newId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001884 enforcePermission(android.Manifest.permission.ASEC_RENAME);
San Mehat207e5382010-02-04 20:46:54 -08001885 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08001886 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08001887
San Mehata181b212010-02-11 06:50:20 -08001888 synchronized (mAsecMountSet) {
San Mehat85451ee2010-02-24 08:54:18 -08001889 /*
Jason parks9ed98bc2011-01-17 09:58:35 -06001890 * Because a mounted container has active internal state which cannot be
San Mehat85451ee2010-02-24 08:54:18 -08001891 * changed while active, we must ensure both ids are not currently mounted.
1892 */
1893 if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
San Mehata181b212010-02-11 06:50:20 -08001894 return StorageResultCode.OperationFailedStorageMounted;
1895 }
1896 }
1897
San Mehatb1043402010-02-05 08:26:50 -08001898 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08001899 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08001900 mConnector.execute("asec", "rename", oldId, newId);
San Mehat4270e1e2010-01-29 05:32:19 -08001901 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08001902 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08001903 }
San Mehata181b212010-02-11 06:50:20 -08001904
San Mehat4270e1e2010-01-29 05:32:19 -08001905 return rc;
San Mehat45f61042010-01-23 08:12:43 -08001906 }
1907
San Mehat4270e1e2010-01-29 05:32:19 -08001908 public String getSecureContainerPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001909 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08001910 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08001911 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08001912
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08001913 final NativeDaemonEvent event;
San Mehat2d66cef2010-03-23 11:12:52 -07001914 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08001915 event = mConnector.execute("asec", "path", id);
1916 event.checkCode(VoldResponseCode.AsecPathResult);
1917 return event.getMessage();
San Mehat2d66cef2010-03-23 11:12:52 -07001918 } catch (NativeDaemonConnectorException e) {
1919 int code = e.getCode();
1920 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Fredrik Helmera20c8ef2011-02-09 16:16:10 +01001921 Slog.i(TAG, String.format("Container '%s' not found", id));
1922 return null;
San Mehat22dd86e2010-01-12 12:21:18 -08001923 } else {
San Mehat2d66cef2010-03-23 11:12:52 -07001924 throw new IllegalStateException(String.format("Unexpected response code %d", code));
San Mehat22dd86e2010-01-12 12:21:18 -08001925 }
1926 }
San Mehat22dd86e2010-01-12 12:21:18 -08001927 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07001928
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07001929 public String getSecureContainerFilesystemPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001930 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07001931 waitForReady();
1932 warnOnNotMounted();
1933
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08001934 final NativeDaemonEvent event;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07001935 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08001936 event = mConnector.execute("asec", "fspath", id);
1937 event.checkCode(VoldResponseCode.AsecPathResult);
1938 return event.getMessage();
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07001939 } catch (NativeDaemonConnectorException e) {
1940 int code = e.getCode();
1941 if (code == VoldResponseCode.OpFailedStorageNotFound) {
1942 Slog.i(TAG, String.format("Container '%s' not found", id));
1943 return null;
1944 } else {
1945 throw new IllegalStateException(String.format("Unexpected response code %d", code));
1946 }
1947 }
1948 }
1949
Jeff Sharkey48877892015-03-18 11:27:19 -07001950 @Override
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07001951 public void finishMediaUpdate() {
Rubin Xucd7a0142015-04-17 23:45:27 +01001952 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
1953 throw new SecurityException("no permission to call finishMediaUpdate()");
1954 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001955 if (mUnmountSignal != null) {
1956 mUnmountSignal.countDown();
1957 } else {
1958 Slog.w(TAG, "Odd, nobody asked to unmount?");
1959 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07001960 }
Kenny Root02c87302010-07-01 08:10:18 -07001961
Kenny Roota02b8b02010-08-05 16:14:17 -07001962 private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
1963 if (callerUid == android.os.Process.SYSTEM_UID) {
1964 return true;
1965 }
1966
Kenny Root02c87302010-07-01 08:10:18 -07001967 if (packageName == null) {
1968 return false;
1969 }
1970
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001971 final int packageUid = mPms.getPackageUid(packageName, UserHandle.getUserId(callerUid));
Kenny Root02c87302010-07-01 08:10:18 -07001972
1973 if (DEBUG_OBB) {
1974 Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
1975 packageUid + ", callerUid = " + callerUid);
1976 }
1977
1978 return callerUid == packageUid;
1979 }
1980
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07001981 public String getMountedObbPath(String rawPath) {
1982 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07001983
Kenny Root02c87302010-07-01 08:10:18 -07001984 waitForReady();
1985 warnOnNotMounted();
1986
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07001987 final ObbState state;
Rubin Xucd7a0142015-04-17 23:45:27 +01001988 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07001989 state = mObbPathToStateMap.get(rawPath);
1990 }
1991 if (state == null) {
1992 Slog.w(TAG, "Failed to find OBB mounted at " + rawPath);
1993 return null;
1994 }
1995
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08001996 final NativeDaemonEvent event;
Kenny Root02c87302010-07-01 08:10:18 -07001997 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07001998 event = mConnector.execute("obb", "path", state.voldPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08001999 event.checkCode(VoldResponseCode.AsecPathResult);
2000 return event.getMessage();
Kenny Root02c87302010-07-01 08:10:18 -07002001 } catch (NativeDaemonConnectorException e) {
2002 int code = e.getCode();
2003 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Kenny Roota02b8b02010-08-05 16:14:17 -07002004 return null;
Kenny Root02c87302010-07-01 08:10:18 -07002005 } else {
2006 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2007 }
2008 }
2009 }
2010
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002011 @Override
2012 public boolean isObbMounted(String rawPath) {
2013 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002014 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002015 return mObbPathToStateMap.containsKey(rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002016 }
Kenny Root02c87302010-07-01 08:10:18 -07002017 }
2018
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002019 @Override
2020 public void mountObb(
2021 String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) {
2022 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2023 Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
2024 Preconditions.checkNotNull(token, "token cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002025
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002026 final int callingUid = Binder.getCallingUid();
2027 final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce);
2028 final ObbAction action = new MountObbAction(obbState, key, callingUid);
Kenny Roota02b8b02010-08-05 16:14:17 -07002029 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
2030
2031 if (DEBUG_OBB)
2032 Slog.i(TAG, "Send to OBB handler: " + action.toString());
Kenny Root02c87302010-07-01 08:10:18 -07002033 }
2034
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002035 @Override
2036 public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
2037 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2038
2039 final ObbState existingState;
Rubin Xucd7a0142015-04-17 23:45:27 +01002040 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002041 existingState = mObbPathToStateMap.get(rawPath);
Kenny Rootf1121dc2010-09-29 07:30:53 -07002042 }
2043
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002044 if (existingState != null) {
2045 // TODO: separate state object from request data
2046 final int callingUid = Binder.getCallingUid();
2047 final ObbState newState = new ObbState(
2048 rawPath, existingState.canonicalPath, callingUid, token, nonce);
2049 final ObbAction action = new UnmountObbAction(newState, force);
2050 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root02c87302010-07-01 08:10:18 -07002051
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002052 if (DEBUG_OBB)
2053 Slog.i(TAG, "Send to OBB handler: " + action.toString());
2054 } else {
2055 Slog.w(TAG, "Unknown OBB mount at " + rawPath);
2056 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002057 }
2058
Ben Komalo444eca22011-09-01 15:17:44 -07002059 @Override
2060 public int getEncryptionState() {
2061 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2062 "no permission to access the crypt keeper");
2063
2064 waitForReady();
2065
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002066 final NativeDaemonEvent event;
Ben Komalo444eca22011-09-01 15:17:44 -07002067 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002068 event = mCryptConnector.execute("cryptfs", "cryptocomplete");
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002069 return Integer.parseInt(event.getMessage());
Ben Komalo444eca22011-09-01 15:17:44 -07002070 } catch (NumberFormatException e) {
2071 // Bad result - unexpected.
2072 Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
2073 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2074 } catch (NativeDaemonConnectorException e) {
2075 // Something bad happened.
2076 Slog.w(TAG, "Error in communicating with cryptfs in validating");
2077 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2078 }
2079 }
2080
Narayan Kamath1653b1d2014-12-17 13:40:36 +00002081 private static String toHex(String password) {
Paul Lawrence8e397362014-01-27 15:22:30 -08002082 if (password == null) {
Narayan Kamath78108a32014-12-16 12:56:23 +00002083 return "";
Paul Lawrence8e397362014-01-27 15:22:30 -08002084 }
2085 byte[] bytes = password.getBytes(StandardCharsets.UTF_8);
Narayan Kamath78108a32014-12-16 12:56:23 +00002086 return new String(HexEncoding.encode(bytes));
Paul Lawrence8e397362014-01-27 15:22:30 -08002087 }
2088
Narayan Kamath1653b1d2014-12-17 13:40:36 +00002089 private static String fromHex(String hexPassword) throws IllegalArgumentException {
Paul Lawrence945490c2014-03-27 16:37:28 +00002090 if (hexPassword == null) {
2091 return null;
2092 }
2093
Narayan Kamath1653b1d2014-12-17 13:40:36 +00002094 final byte[] bytes = HexEncoding.decode(hexPassword.toCharArray(), false);
Narayan Kamath78108a32014-12-16 12:56:23 +00002095 return new String(bytes, StandardCharsets.UTF_8);
Paul Lawrence945490c2014-03-27 16:37:28 +00002096 }
2097
Ben Komalo444eca22011-09-01 15:17:44 -07002098 @Override
Jason parks5af0b912010-11-29 09:05:25 -06002099 public int decryptStorage(String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002100 if (TextUtils.isEmpty(password)) {
2101 throw new IllegalArgumentException("password cannot be empty");
Jason parks5af0b912010-11-29 09:05:25 -06002102 }
2103
Jason parks8888c592011-01-20 22:46:41 -06002104 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2105 "no permission to access the crypt keeper");
Jason parks5af0b912010-11-29 09:05:25 -06002106
2107 waitForReady();
2108
2109 if (DEBUG_EVENTS) {
2110 Slog.i(TAG, "decrypting storage...");
2111 }
2112
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002113 final NativeDaemonEvent event;
Jason parks5af0b912010-11-29 09:05:25 -06002114 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002115 event = mCryptConnector.execute("cryptfs", "checkpw", new SensitiveArg(toHex(password)));
Jason parks9ed98bc2011-01-17 09:58:35 -06002116
Fredrik Roubertda6aedf2011-12-20 17:34:43 +01002117 final int code = Integer.parseInt(event.getMessage());
Jason parks9ed98bc2011-01-17 09:58:35 -06002118 if (code == 0) {
2119 // Decrypt was successful. Post a delayed message before restarting in order
2120 // to let the UI to clear itself
2121 mHandler.postDelayed(new Runnable() {
2122 public void run() {
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002123 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002124 mCryptConnector.execute("cryptfs", "restart");
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002125 } catch (NativeDaemonConnectorException e) {
2126 Slog.e(TAG, "problem executing in background", e);
2127 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002128 }
Jason parksf7b3cd42011-01-27 09:28:25 -06002129 }, 1000); // 1 second
Jason parks9ed98bc2011-01-17 09:58:35 -06002130 }
2131
2132 return code;
Jason parks5af0b912010-11-29 09:05:25 -06002133 } catch (NativeDaemonConnectorException e) {
2134 // Decryption failed
2135 return e.getCode();
2136 }
Jason parks5af0b912010-11-29 09:05:25 -06002137 }
2138
Paul Lawrence46791e72014-04-03 09:10:26 -07002139 public int encryptStorage(int type, String password) {
2140 if (TextUtils.isEmpty(password) && type != StorageManager.CRYPT_TYPE_DEFAULT) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002141 throw new IllegalArgumentException("password cannot be empty");
Jason parks56aa5322011-01-07 09:01:15 -06002142 }
2143
Jason parks8888c592011-01-20 22:46:41 -06002144 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2145 "no permission to access the crypt keeper");
Jason parks56aa5322011-01-07 09:01:15 -06002146
2147 waitForReady();
2148
2149 if (DEBUG_EVENTS) {
Jason parks8888c592011-01-20 22:46:41 -06002150 Slog.i(TAG, "encrypting storage...");
Jason parks56aa5322011-01-07 09:01:15 -06002151 }
2152
2153 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002154 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace", CRYPTO_TYPES[type],
Paul Lawrence8e397362014-01-27 15:22:30 -08002155 new SensitiveArg(toHex(password)));
Jason parks56aa5322011-01-07 09:01:15 -06002156 } catch (NativeDaemonConnectorException e) {
2157 // Encryption failed
2158 return e.getCode();
2159 }
2160
2161 return 0;
2162 }
2163
Paul Lawrence8e397362014-01-27 15:22:30 -08002164 /** Set the password for encrypting the master key.
2165 * @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
2166 * @param password The password to set.
2167 */
2168 public int changeEncryptionPassword(int type, String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002169 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2170 "no permission to access the crypt keeper");
2171
2172 waitForReady();
2173
2174 if (DEBUG_EVENTS) {
2175 Slog.i(TAG, "changing encryption password...");
2176 }
2177
2178 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002179 NativeDaemonEvent event = mCryptConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type],
Svetoslav16e4a1a2014-09-29 18:16:20 -07002180 new SensitiveArg(toHex(password)));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002181 return Integer.parseInt(event.getMessage());
Jason parksf7b3cd42011-01-27 09:28:25 -06002182 } catch (NativeDaemonConnectorException e) {
2183 // Encryption failed
2184 return e.getCode();
2185 }
2186 }
2187
Christopher Tate32418be2011-10-10 13:51:12 -07002188 /**
2189 * Validate a user-supplied password string with cryptfs
2190 */
2191 @Override
2192 public int verifyEncryptionPassword(String password) throws RemoteException {
2193 // Only the system process is permitted to validate passwords
2194 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2195 throw new SecurityException("no permission to access the crypt keeper");
2196 }
2197
2198 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2199 "no permission to access the crypt keeper");
2200
2201 if (TextUtils.isEmpty(password)) {
2202 throw new IllegalArgumentException("password cannot be empty");
2203 }
2204
2205 waitForReady();
2206
2207 if (DEBUG_EVENTS) {
2208 Slog.i(TAG, "validating encryption password...");
2209 }
2210
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002211 final NativeDaemonEvent event;
Christopher Tate32418be2011-10-10 13:51:12 -07002212 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002213 event = mCryptConnector.execute("cryptfs", "verifypw", new SensitiveArg(toHex(password)));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002214 Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
2215 return Integer.parseInt(event.getMessage());
Christopher Tate32418be2011-10-10 13:51:12 -07002216 } catch (NativeDaemonConnectorException e) {
2217 // Encryption failed
2218 return e.getCode();
2219 }
2220 }
2221
Paul Lawrence8e397362014-01-27 15:22:30 -08002222 /**
2223 * Get the type of encryption used to encrypt the master key.
2224 * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
2225 */
2226 @Override
Svetoslav16e4a1a2014-09-29 18:16:20 -07002227 public int getPasswordType() {
Paul Lawrence8e397362014-01-27 15:22:30 -08002228
2229 waitForReady();
2230
2231 final NativeDaemonEvent event;
2232 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002233 event = mCryptConnector.execute("cryptfs", "getpwtype");
Paul Lawrence8e397362014-01-27 15:22:30 -08002234 for (int i = 0; i < CRYPTO_TYPES.length; ++i) {
2235 if (CRYPTO_TYPES[i].equals(event.getMessage()))
2236 return i;
2237 }
2238
2239 throw new IllegalStateException("unexpected return from cryptfs");
2240 } catch (NativeDaemonConnectorException e) {
2241 throw e.rethrowAsParcelableException();
2242 }
2243 }
2244
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002245 /**
2246 * Set a field in the crypto header.
2247 * @param field field to set
2248 * @param contents contents to set in field
2249 */
2250 @Override
2251 public void setField(String field, String contents) throws RemoteException {
2252
2253 waitForReady();
2254
2255 final NativeDaemonEvent event;
2256 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002257 event = mCryptConnector.execute("cryptfs", "setfield", field, contents);
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002258 } catch (NativeDaemonConnectorException e) {
2259 throw e.rethrowAsParcelableException();
2260 }
2261 }
2262
2263 /**
2264 * Gets a field from the crypto header.
2265 * @param field field to get
2266 * @return contents of field
2267 */
2268 @Override
2269 public String getField(String field) throws RemoteException {
2270
2271 waitForReady();
2272
2273 final NativeDaemonEvent event;
2274 try {
2275 final String[] contents = NativeDaemonEvent.filterMessageList(
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002276 mCryptConnector.executeForList("cryptfs", "getfield", field),
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002277 VoldResponseCode.CryptfsGetfieldResult);
2278 String result = new String();
2279 for (String content : contents) {
2280 result += content;
2281 }
2282 return result;
2283 } catch (NativeDaemonConnectorException e) {
2284 throw e.rethrowAsParcelableException();
2285 }
2286 }
2287
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002288 @Override
Paul Lawrence945490c2014-03-27 16:37:28 +00002289 public String getPassword() throws RemoteException {
Rubin Xucd7a0142015-04-17 23:45:27 +01002290 mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE,
2291 "only keyguard can retrieve password");
Paul Lawrence945490c2014-03-27 16:37:28 +00002292 if (!isReady()) {
2293 return new String();
2294 }
2295
2296 final NativeDaemonEvent event;
2297 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002298 event = mCryptConnector.execute("cryptfs", "getpw");
Paul Lawrence24063b52015-01-06 13:11:23 -08002299 if ("-1".equals(event.getMessage())) {
2300 // -1 equals no password
2301 return null;
2302 }
Paul Lawrence945490c2014-03-27 16:37:28 +00002303 return fromHex(event.getMessage());
2304 } catch (NativeDaemonConnectorException e) {
2305 throw e.rethrowAsParcelableException();
Paul Lawrence24063b52015-01-06 13:11:23 -08002306 } catch (IllegalArgumentException e) {
2307 Slog.e(TAG, "Invalid response to getPassword");
2308 return null;
Paul Lawrence945490c2014-03-27 16:37:28 +00002309 }
2310 }
2311
2312 @Override
2313 public void clearPassword() throws RemoteException {
2314 if (!isReady()) {
2315 return;
2316 }
2317
2318 final NativeDaemonEvent event;
2319 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002320 event = mCryptConnector.execute("cryptfs", "clearpw");
Paul Lawrence945490c2014-03-27 16:37:28 +00002321 } catch (NativeDaemonConnectorException e) {
2322 throw e.rethrowAsParcelableException();
2323 }
2324 }
2325
2326 @Override
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002327 public int mkdirs(String callingPkg, String appPath) {
2328 final int userId = UserHandle.getUserId(Binder.getCallingUid());
2329 final UserEnvironment userEnv = new UserEnvironment(userId);
2330
2331 // Validate that reported package name belongs to caller
2332 final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
2333 Context.APP_OPS_SERVICE);
2334 appOps.checkPackage(Binder.getCallingUid(), callingPkg);
2335
Jeff Sharkey48877892015-03-18 11:27:19 -07002336 File appFile = null;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002337 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07002338 appFile = new File(appPath).getCanonicalFile();
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002339 } catch (IOException e) {
2340 Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
2341 return -1;
2342 }
2343
2344 // Try translating the app path into a vold path, but require that it
2345 // belong to the calling package.
Jeff Sharkey48877892015-03-18 11:27:19 -07002346 if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) ||
2347 FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) ||
2348 FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) {
2349 appPath = appFile.getAbsolutePath();
2350 if (!appPath.endsWith("/")) {
2351 appPath = appPath + "/";
2352 }
2353
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002354 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07002355 mConnector.execute("volume", "mkdirs", appPath);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002356 return 0;
2357 } catch (NativeDaemonConnectorException e) {
2358 return e.getCode();
2359 }
2360 }
2361
Jeff Sharkey48877892015-03-18 11:27:19 -07002362 throw new SecurityException("Invalid mkdirs path: " + appFile);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002363 }
2364
2365 @Override
Jeff Sharkey48877892015-03-18 11:27:19 -07002366 public StorageVolume[] getVolumeList(int userId) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002367 final ArrayList<StorageVolume> res = new ArrayList<>();
Jeff Sharkey48877892015-03-18 11:27:19 -07002368 boolean foundPrimary = false;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002369
Jeff Sharkey48877892015-03-18 11:27:19 -07002370 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002371 for (int i = 0; i < mVolumes.size(); i++) {
2372 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey48877892015-03-18 11:27:19 -07002373 if (vol.isVisibleToUser(userId)) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002374 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -07002375 if (vol.isPrimary()) {
2376 res.add(0, userVol);
2377 foundPrimary = true;
2378 } else {
2379 res.add(userVol);
2380 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002381 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002382 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002383 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002384
2385 if (!foundPrimary) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002386 Log.w(TAG, "No primary storage defined yet; hacking together a stub");
Jeff Sharkey48877892015-03-18 11:27:19 -07002387
2388 final boolean primaryPhysical = SystemProperties.getBoolean(
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002389 StorageManager.PROP_PRIMARY_PHYSICAL, false);
Jeff Sharkey48877892015-03-18 11:27:19 -07002390
2391 final String id = "stub_primary";
2392 final File path = Environment.getLegacyExternalStorageDirectory();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002393 final String description = mContext.getString(android.R.string.unknownName);
Jeff Sharkey48877892015-03-18 11:27:19 -07002394 final boolean primary = true;
2395 final boolean removable = primaryPhysical;
2396 final boolean emulated = !primaryPhysical;
2397 final long mtpReserveSize = 0L;
2398 final boolean allowMassStorage = false;
2399 final long maxFileSize = 0L;
2400 final UserHandle owner = new UserHandle(userId);
2401 final String uuid = null;
Jeff Sharkey48877892015-03-18 11:27:19 -07002402 final String state = Environment.MEDIA_REMOVED;
2403
2404 res.add(0, new StorageVolume(id, MtpStorage.getStorageIdForIndex(0), path,
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002405 description, primary, removable, emulated, mtpReserveSize,
2406 allowMassStorage, maxFileSize, owner, uuid, state));
Jeff Sharkey48877892015-03-18 11:27:19 -07002407 }
2408
2409 return res.toArray(new StorageVolume[res.size()]);
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002410 }
2411
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002412 @Override
2413 public DiskInfo[] getDisks() {
2414 synchronized (mLock) {
2415 final DiskInfo[] res = new DiskInfo[mDisks.size()];
2416 for (int i = 0; i < mDisks.size(); i++) {
2417 res[i] = mDisks.valueAt(i);
2418 }
2419 return res;
2420 }
2421 }
2422
2423 @Override
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07002424 public VolumeInfo[] getVolumes(int flags) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002425 synchronized (mLock) {
2426 final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
2427 for (int i = 0; i < mVolumes.size(); i++) {
2428 res[i] = mVolumes.valueAt(i);
2429 }
2430 return res;
2431 }
2432 }
2433
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07002434 @Override
2435 public VolumeRecord[] getVolumeRecords(int flags) {
2436 synchronized (mLock) {
2437 final VolumeRecord[] res = new VolumeRecord[mRecords.size()];
2438 for (int i = 0; i < mRecords.size(); i++) {
2439 res[i] = mRecords.valueAt(i);
2440 }
2441 return res;
2442 }
2443 }
2444
Kenny Rootaf9d6672010-10-08 09:21:39 -07002445 private void addObbStateLocked(ObbState obbState) throws RemoteException {
2446 final IBinder binder = obbState.getBinder();
2447 List<ObbState> obbStates = mObbMounts.get(binder);
Kenny Root5919ac62010-10-05 09:49:40 -07002448
Kenny Rootaf9d6672010-10-08 09:21:39 -07002449 if (obbStates == null) {
2450 obbStates = new ArrayList<ObbState>();
2451 mObbMounts.put(binder, obbStates);
2452 } else {
2453 for (final ObbState o : obbStates) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002454 if (o.rawPath.equals(obbState.rawPath)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07002455 throw new IllegalStateException("Attempt to add ObbState twice. "
2456 + "This indicates an error in the MountService logic.");
Kenny Root5919ac62010-10-05 09:49:40 -07002457 }
2458 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002459 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07002460
2461 obbStates.add(obbState);
2462 try {
2463 obbState.link();
2464 } catch (RemoteException e) {
2465 /*
2466 * The binder died before we could link it, so clean up our state
2467 * and return failure.
2468 */
2469 obbStates.remove(obbState);
2470 if (obbStates.isEmpty()) {
2471 mObbMounts.remove(binder);
2472 }
2473
2474 // Rethrow the error so mountObb can get it
2475 throw e;
2476 }
2477
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002478 mObbPathToStateMap.put(obbState.rawPath, obbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07002479 }
2480
Kenny Rootaf9d6672010-10-08 09:21:39 -07002481 private void removeObbStateLocked(ObbState obbState) {
2482 final IBinder binder = obbState.getBinder();
2483 final List<ObbState> obbStates = mObbMounts.get(binder);
2484 if (obbStates != null) {
2485 if (obbStates.remove(obbState)) {
2486 obbState.unlink();
Kenny Root05105f72010-09-22 17:29:43 -07002487 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07002488 if (obbStates.isEmpty()) {
2489 mObbMounts.remove(binder);
2490 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002491 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002492
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002493 mObbPathToStateMap.remove(obbState.rawPath);
Kenny Root38cf8862010-09-26 14:18:51 -07002494 }
2495
Kenny Roota02b8b02010-08-05 16:14:17 -07002496 private class ObbActionHandler extends Handler {
2497 private boolean mBound = false;
Kenny Root480afe72010-10-07 10:17:50 -07002498 private final List<ObbAction> mActions = new LinkedList<ObbAction>();
Kenny Roota02b8b02010-08-05 16:14:17 -07002499
2500 ObbActionHandler(Looper l) {
2501 super(l);
2502 }
2503
2504 @Override
2505 public void handleMessage(Message msg) {
2506 switch (msg.what) {
2507 case OBB_RUN_ACTION: {
Kenny Root480afe72010-10-07 10:17:50 -07002508 final ObbAction action = (ObbAction) msg.obj;
Kenny Roota02b8b02010-08-05 16:14:17 -07002509
2510 if (DEBUG_OBB)
2511 Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
2512
2513 // If a bind was already initiated we don't really
2514 // need to do anything. The pending install
2515 // will be processed later on.
2516 if (!mBound) {
2517 // If this is the only one pending we might
2518 // have to bind to the service again.
2519 if (!connectToService()) {
2520 Slog.e(TAG, "Failed to bind to media container service");
2521 action.handleError();
2522 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07002523 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002524 }
Kenny Root735de3b2010-09-30 14:11:39 -07002525
Kenny Root735de3b2010-09-30 14:11:39 -07002526 mActions.add(action);
Kenny Roota02b8b02010-08-05 16:14:17 -07002527 break;
2528 }
2529 case OBB_MCS_BOUND: {
2530 if (DEBUG_OBB)
2531 Slog.i(TAG, "OBB_MCS_BOUND");
2532 if (msg.obj != null) {
2533 mContainerService = (IMediaContainerService) msg.obj;
2534 }
2535 if (mContainerService == null) {
2536 // Something seriously wrong. Bail out
2537 Slog.e(TAG, "Cannot bind to media container service");
2538 for (ObbAction action : mActions) {
2539 // Indicate service bind error
2540 action.handleError();
2541 }
2542 mActions.clear();
2543 } else if (mActions.size() > 0) {
Kenny Root480afe72010-10-07 10:17:50 -07002544 final ObbAction action = mActions.get(0);
Kenny Roota02b8b02010-08-05 16:14:17 -07002545 if (action != null) {
2546 action.execute(this);
2547 }
2548 } else {
2549 // Should never happen ideally.
2550 Slog.w(TAG, "Empty queue");
2551 }
2552 break;
2553 }
2554 case OBB_MCS_RECONNECT: {
2555 if (DEBUG_OBB)
2556 Slog.i(TAG, "OBB_MCS_RECONNECT");
2557 if (mActions.size() > 0) {
2558 if (mBound) {
2559 disconnectService();
2560 }
2561 if (!connectToService()) {
2562 Slog.e(TAG, "Failed to bind to media container service");
2563 for (ObbAction action : mActions) {
2564 // Indicate service bind error
2565 action.handleError();
2566 }
2567 mActions.clear();
2568 }
2569 }
2570 break;
2571 }
2572 case OBB_MCS_UNBIND: {
2573 if (DEBUG_OBB)
2574 Slog.i(TAG, "OBB_MCS_UNBIND");
2575
2576 // Delete pending install
2577 if (mActions.size() > 0) {
2578 mActions.remove(0);
2579 }
2580 if (mActions.size() == 0) {
2581 if (mBound) {
2582 disconnectService();
2583 }
2584 } else {
2585 // There are more pending requests in queue.
2586 // Just post MCS_BOUND message to trigger processing
2587 // of next pending install.
2588 mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
2589 }
2590 break;
2591 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07002592 case OBB_FLUSH_MOUNT_STATE: {
2593 final String path = (String) msg.obj;
2594
2595 if (DEBUG_OBB)
2596 Slog.i(TAG, "Flushing all OBB state for path " + path);
2597
2598 synchronized (mObbMounts) {
2599 final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
2600
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002601 final Iterator<ObbState> i = mObbPathToStateMap.values().iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07002602 while (i.hasNext()) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002603 final ObbState state = i.next();
Kenny Rootaf9d6672010-10-08 09:21:39 -07002604
2605 /*
2606 * If this entry's source file is in the volume path
2607 * that got unmounted, remove it because it's no
2608 * longer valid.
2609 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002610 if (state.canonicalPath.startsWith(path)) {
2611 obbStatesToRemove.add(state);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002612 }
2613 }
2614
2615 for (final ObbState obbState : obbStatesToRemove) {
2616 if (DEBUG_OBB)
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002617 Slog.i(TAG, "Removing state for " + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002618
2619 removeObbStateLocked(obbState);
2620
2621 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002622 obbState.token.onObbResult(obbState.rawPath, obbState.nonce,
Kenny Rootaf9d6672010-10-08 09:21:39 -07002623 OnObbStateChangeListener.UNMOUNTED);
2624 } catch (RemoteException e) {
2625 Slog.i(TAG, "Couldn't send unmount notification for OBB: "
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002626 + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002627 }
2628 }
2629 }
2630 break;
2631 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002632 }
2633 }
2634
2635 private boolean connectToService() {
2636 if (DEBUG_OBB)
2637 Slog.i(TAG, "Trying to bind to DefaultContainerService");
2638
2639 Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
2640 if (mContext.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE)) {
2641 mBound = true;
2642 return true;
2643 }
2644 return false;
2645 }
2646
2647 private void disconnectService() {
2648 mContainerService = null;
2649 mBound = false;
2650 mContext.unbindService(mDefContainerConn);
2651 }
2652 }
2653
2654 abstract class ObbAction {
2655 private static final int MAX_RETRIES = 3;
2656 private int mRetries;
2657
2658 ObbState mObbState;
2659
2660 ObbAction(ObbState obbState) {
2661 mObbState = obbState;
2662 }
2663
2664 public void execute(ObbActionHandler handler) {
2665 try {
2666 if (DEBUG_OBB)
Ben Komalo444eca22011-09-01 15:17:44 -07002667 Slog.i(TAG, "Starting to execute action: " + toString());
Kenny Roota02b8b02010-08-05 16:14:17 -07002668 mRetries++;
2669 if (mRetries > MAX_RETRIES) {
2670 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
Kenny Root480afe72010-10-07 10:17:50 -07002671 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07002672 handleError();
2673 return;
2674 } else {
2675 handleExecute();
2676 if (DEBUG_OBB)
2677 Slog.i(TAG, "Posting install MCS_UNBIND");
2678 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
2679 }
2680 } catch (RemoteException e) {
2681 if (DEBUG_OBB)
2682 Slog.i(TAG, "Posting install MCS_RECONNECT");
2683 mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
2684 } catch (Exception e) {
2685 if (DEBUG_OBB)
2686 Slog.d(TAG, "Error handling OBB action", e);
2687 handleError();
Kenny Root17eb6fb2010-10-06 15:02:52 -07002688 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07002689 }
2690 }
2691
Kenny Root05105f72010-09-22 17:29:43 -07002692 abstract void handleExecute() throws RemoteException, IOException;
Kenny Roota02b8b02010-08-05 16:14:17 -07002693 abstract void handleError();
Kenny Root38cf8862010-09-26 14:18:51 -07002694
2695 protected ObbInfo getObbInfo() throws IOException {
2696 ObbInfo obbInfo;
2697 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002698 obbInfo = mContainerService.getObbInfo(mObbState.ownerPath);
Kenny Root38cf8862010-09-26 14:18:51 -07002699 } catch (RemoteException e) {
2700 Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002701 + mObbState.ownerPath);
Kenny Root38cf8862010-09-26 14:18:51 -07002702 obbInfo = null;
2703 }
2704 if (obbInfo == null) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002705 throw new IOException("Couldn't read OBB file: " + mObbState.ownerPath);
Kenny Root38cf8862010-09-26 14:18:51 -07002706 }
2707 return obbInfo;
2708 }
2709
Kenny Rootaf9d6672010-10-08 09:21:39 -07002710 protected void sendNewStatusOrIgnore(int status) {
2711 if (mObbState == null || mObbState.token == null) {
2712 return;
2713 }
2714
Kenny Root38cf8862010-09-26 14:18:51 -07002715 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002716 mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
Kenny Root38cf8862010-09-26 14:18:51 -07002717 } catch (RemoteException e) {
2718 Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
2719 }
2720 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002721 }
2722
2723 class MountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07002724 private final String mKey;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002725 private final int mCallingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07002726
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002727 MountObbAction(ObbState obbState, String key, int callingUid) {
Kenny Roota02b8b02010-08-05 16:14:17 -07002728 super(obbState);
2729 mKey = key;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002730 mCallingUid = callingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07002731 }
2732
Jason parks5af0b912010-11-29 09:05:25 -06002733 @Override
Kenny Root735de3b2010-09-30 14:11:39 -07002734 public void handleExecute() throws IOException, RemoteException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07002735 waitForReady();
2736 warnOnNotMounted();
2737
Kenny Root38cf8862010-09-26 14:18:51 -07002738 final ObbInfo obbInfo = getObbInfo();
2739
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002740 if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07002741 Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
2742 + " which is owned by " + obbInfo.packageName);
2743 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
2744 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07002745 }
2746
Kenny Rootaf9d6672010-10-08 09:21:39 -07002747 final boolean isMounted;
2748 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002749 isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002750 }
2751 if (isMounted) {
2752 Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
2753 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
2754 return;
2755 }
2756
Kenny Rootaf9d6672010-10-08 09:21:39 -07002757 final String hashedKey;
2758 if (mKey == null) {
2759 hashedKey = "none";
2760 } else {
Kenny Rootaf9d6672010-10-08 09:21:39 -07002761 try {
Kenny Root3b1abba2010-10-13 15:00:07 -07002762 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
2763
2764 KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
2765 PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
2766 SecretKey key = factory.generateSecret(ks);
2767 BigInteger bi = new BigInteger(key.getEncoded());
2768 hashedKey = bi.toString(16);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002769 } catch (NoSuchAlgorithmException e) {
Kenny Root3b1abba2010-10-13 15:00:07 -07002770 Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
2771 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
2772 return;
2773 } catch (InvalidKeySpecException e) {
2774 Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
2775 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root38cf8862010-09-26 14:18:51 -07002776 return;
2777 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07002778 }
Kenny Root38cf8862010-09-26 14:18:51 -07002779
Kenny Rootaf9d6672010-10-08 09:21:39 -07002780 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07002781 try {
Jeff Sharkey56cd6462013-06-07 15:09:15 -07002782 mConnector.execute("obb", "mount", mObbState.voldPath, new SensitiveArg(hashedKey),
2783 mObbState.ownerGid);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002784 } catch (NativeDaemonConnectorException e) {
2785 int code = e.getCode();
2786 if (code != VoldResponseCode.OpFailedStorageBusy) {
2787 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07002788 }
2789 }
2790
Kenny Rootaf9d6672010-10-08 09:21:39 -07002791 if (rc == StorageResultCode.OperationSucceeded) {
2792 if (DEBUG_OBB)
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002793 Slog.d(TAG, "Successfully mounted OBB " + mObbState.voldPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002794
2795 synchronized (mObbMounts) {
2796 addObbStateLocked(mObbState);
2797 }
2798
2799 sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
Kenny Root02c87302010-07-01 08:10:18 -07002800 } else {
Kenny Root05105f72010-09-22 17:29:43 -07002801 Slog.e(TAG, "Couldn't mount OBB file: " + rc);
Kenny Roota02b8b02010-08-05 16:14:17 -07002802
Kenny Rootaf9d6672010-10-08 09:21:39 -07002803 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
Kenny Root02c87302010-07-01 08:10:18 -07002804 }
2805 }
2806
Jason parks5af0b912010-11-29 09:05:25 -06002807 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07002808 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07002809 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root02c87302010-07-01 08:10:18 -07002810 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002811
2812 @Override
2813 public String toString() {
2814 StringBuilder sb = new StringBuilder();
2815 sb.append("MountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002816 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07002817 sb.append('}');
2818 return sb.toString();
2819 }
2820 }
2821
2822 class UnmountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07002823 private final boolean mForceUnmount;
Kenny Roota02b8b02010-08-05 16:14:17 -07002824
2825 UnmountObbAction(ObbState obbState, boolean force) {
2826 super(obbState);
2827 mForceUnmount = force;
2828 }
2829
Jason parks5af0b912010-11-29 09:05:25 -06002830 @Override
Kenny Root38cf8862010-09-26 14:18:51 -07002831 public void handleExecute() throws IOException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07002832 waitForReady();
2833 warnOnNotMounted();
2834
Kenny Root38cf8862010-09-26 14:18:51 -07002835 final ObbInfo obbInfo = getObbInfo();
Kenny Roota02b8b02010-08-05 16:14:17 -07002836
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002837 final ObbState existingState;
Kenny Root38cf8862010-09-26 14:18:51 -07002838 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002839 existingState = mObbPathToStateMap.get(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002840 }
Kenny Root38cf8862010-09-26 14:18:51 -07002841
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002842 if (existingState == null) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07002843 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
2844 return;
2845 }
2846
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002847 if (existingState.ownerGid != mObbState.ownerGid) {
2848 Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
2849 + " (owned by GID " + existingState.ownerGid + ")");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002850 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
2851 return;
2852 }
2853
Kenny Rootaf9d6672010-10-08 09:21:39 -07002854 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07002855 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002856 final Command cmd = new Command("obb", "unmount", mObbState.voldPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002857 if (mForceUnmount) {
2858 cmd.appendArg("force");
2859 }
2860 mConnector.execute(cmd);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002861 } catch (NativeDaemonConnectorException e) {
2862 int code = e.getCode();
2863 if (code == VoldResponseCode.OpFailedStorageBusy) {
2864 rc = StorageResultCode.OperationFailedStorageBusy;
2865 } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
2866 // If it's not mounted then we've already won.
2867 rc = StorageResultCode.OperationSucceeded;
2868 } else {
2869 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07002870 }
2871 }
2872
Kenny Rootaf9d6672010-10-08 09:21:39 -07002873 if (rc == StorageResultCode.OperationSucceeded) {
2874 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002875 removeObbStateLocked(existingState);
Kenny Root38cf8862010-09-26 14:18:51 -07002876 }
2877
Kenny Rootaf9d6672010-10-08 09:21:39 -07002878 sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
Kenny Roota02b8b02010-08-05 16:14:17 -07002879 } else {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002880 Slog.w(TAG, "Could not unmount OBB: " + existingState);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002881 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
Kenny Roota02b8b02010-08-05 16:14:17 -07002882 }
2883 }
2884
Jason parks5af0b912010-11-29 09:05:25 -06002885 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07002886 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07002887 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Roota02b8b02010-08-05 16:14:17 -07002888 }
2889
2890 @Override
2891 public String toString() {
2892 StringBuilder sb = new StringBuilder();
2893 sb.append("UnmountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002894 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07002895 sb.append(",force=");
2896 sb.append(mForceUnmount);
Kenny Roota02b8b02010-08-05 16:14:17 -07002897 sb.append('}');
2898 return sb.toString();
2899 }
Kenny Root02c87302010-07-01 08:10:18 -07002900 }
Kenny Root38cf8862010-09-26 14:18:51 -07002901
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -08002902 @VisibleForTesting
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002903 public static String buildObbPath(final String canonicalPath, int userId, boolean forVold) {
2904 // TODO: allow caller to provide Environment for full testing
Jeff Sharkey1abdb712013-08-11 16:28:14 -07002905 // TODO: extend to support OBB mounts on secondary external storage
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002906
2907 // Only adjust paths when storage is emulated
2908 if (!Environment.isExternalStorageEmulated()) {
2909 return canonicalPath;
2910 }
2911
2912 String path = canonicalPath.toString();
2913
2914 // First trim off any external storage prefix
2915 final UserEnvironment userEnv = new UserEnvironment(userId);
2916
2917 // /storage/emulated/0
Jeff Sharkey1abdb712013-08-11 16:28:14 -07002918 final String externalPath = userEnv.getExternalStorageDirectory().getAbsolutePath();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002919 // /storage/emulated_legacy
2920 final String legacyExternalPath = Environment.getLegacyExternalStorageDirectory()
Jeff Sharkey1abdb712013-08-11 16:28:14 -07002921 .getAbsolutePath();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002922
2923 if (path.startsWith(externalPath)) {
2924 path = path.substring(externalPath.length() + 1);
2925 } else if (path.startsWith(legacyExternalPath)) {
2926 path = path.substring(legacyExternalPath.length() + 1);
2927 } else {
2928 return canonicalPath;
2929 }
2930
2931 // Handle special OBB paths on emulated storage
2932 final String obbPath = "Android/obb";
2933 if (path.startsWith(obbPath)) {
2934 path = path.substring(obbPath.length() + 1);
2935
Jeff Sharkey48877892015-03-18 11:27:19 -07002936 final UserEnvironment ownerEnv = new UserEnvironment(UserHandle.USER_OWNER);
2937 return new File(ownerEnv.buildExternalStorageAndroidObbDirs()[0], path)
2938 .getAbsolutePath();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002939 }
2940
2941 // Handle normal external storage paths
Jeff Sharkey48877892015-03-18 11:27:19 -07002942 return new File(userEnv.getExternalStorageDirectory(), path).getAbsolutePath();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002943 }
2944
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07002945 private static class Callbacks extends Handler {
2946 private static final int MSG_STORAGE_STATE_CHANGED = 1;
2947 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -07002948 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
2949 private static final int MSG_VOLUME_FORGOTTEN = 4;
2950 private static final int MSG_DISK_SCANNED = 5;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07002951
2952 private final RemoteCallbackList<IMountServiceListener>
2953 mCallbacks = new RemoteCallbackList<>();
2954
2955 public Callbacks(Looper looper) {
2956 super(looper);
2957 }
2958
2959 public void register(IMountServiceListener callback) {
2960 mCallbacks.register(callback);
2961 }
2962
2963 public void unregister(IMountServiceListener callback) {
2964 mCallbacks.unregister(callback);
2965 }
2966
2967 @Override
2968 public void handleMessage(Message msg) {
2969 final SomeArgs args = (SomeArgs) msg.obj;
2970 final int n = mCallbacks.beginBroadcast();
2971 for (int i = 0; i < n; i++) {
2972 final IMountServiceListener callback = mCallbacks.getBroadcastItem(i);
2973 try {
2974 invokeCallback(callback, msg.what, args);
2975 } catch (RemoteException ignored) {
2976 }
2977 }
2978 mCallbacks.finishBroadcast();
2979 args.recycle();
2980 }
2981
2982 private void invokeCallback(IMountServiceListener callback, int what, SomeArgs args)
2983 throws RemoteException {
2984 switch (what) {
2985 case MSG_STORAGE_STATE_CHANGED: {
2986 callback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
2987 (String) args.arg3);
2988 break;
2989 }
2990 case MSG_VOLUME_STATE_CHANGED: {
2991 callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
2992 break;
2993 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07002994 case MSG_VOLUME_RECORD_CHANGED: {
2995 callback.onVolumeRecordChanged((VolumeRecord) args.arg1);
2996 break;
2997 }
2998 case MSG_VOLUME_FORGOTTEN: {
2999 callback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003000 break;
3001 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003002 case MSG_DISK_SCANNED: {
3003 callback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003004 break;
3005 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003006 }
3007 }
3008
3009 private void notifyStorageStateChanged(String path, String oldState, String newState) {
3010 final SomeArgs args = SomeArgs.obtain();
3011 args.arg1 = path;
3012 args.arg2 = oldState;
3013 args.arg3 = newState;
3014 obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
3015 }
3016
3017 private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
3018 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003019 args.arg1 = vol.clone();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003020 args.argi2 = oldState;
3021 args.argi3 = newState;
3022 obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
3023 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003024
Jeff Sharkey50a05452015-04-29 11:24:52 -07003025 private void notifyVolumeRecordChanged(VolumeRecord rec) {
3026 final SomeArgs args = SomeArgs.obtain();
3027 args.arg1 = rec.clone();
3028 obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
3029 }
3030
3031 private void notifyVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003032 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003033 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003034 obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003035 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003036
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003037 private void notifyDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003038 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003039 args.arg1 = disk.clone();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003040 args.argi2 = volumeCount;
3041 obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003042 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003043 }
3044
Kenny Root38cf8862010-09-26 14:18:51 -07003045 @Override
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003046 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
3047 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
3048
3049 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003050 synchronized (mLock) {
3051 pw.println("Disks:");
3052 pw.increaseIndent();
3053 for (int i = 0; i < mDisks.size(); i++) {
3054 final DiskInfo disk = mDisks.valueAt(i);
3055 disk.dump(pw);
3056 }
3057 pw.decreaseIndent();
3058
3059 pw.println();
3060 pw.println("Volumes:");
3061 pw.increaseIndent();
3062 for (int i = 0; i < mVolumes.size(); i++) {
3063 final VolumeInfo vol = mVolumes.valueAt(i);
3064 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue;
3065 vol.dump(pw);
3066 }
3067 pw.decreaseIndent();
3068
3069 pw.println();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003070 pw.println("Records:");
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003071 pw.increaseIndent();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003072 for (int i = 0; i < mRecords.size(); i++) {
3073 final VolumeRecord note = mRecords.valueAt(i);
3074 note.dump(pw);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003075 }
3076 pw.decreaseIndent();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07003077
3078 pw.println();
3079 pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07003080 pw.println("Force adoptable: " + mForceAdoptable);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003081 }
Kenny Root38cf8862010-09-26 14:18:51 -07003082
Kenny Root38cf8862010-09-26 14:18:51 -07003083 synchronized (mObbMounts) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003084 pw.println();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003085 pw.println("mObbMounts:");
3086 pw.increaseIndent();
3087 final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet()
3088 .iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003089 while (binders.hasNext()) {
3090 Entry<IBinder, List<ObbState>> e = binders.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003091 pw.println(e.getKey() + ":");
3092 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003093 final List<ObbState> obbStates = e.getValue();
Kenny Root38cf8862010-09-26 14:18:51 -07003094 for (final ObbState obbState : obbStates) {
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003095 pw.println(obbState);
Kenny Root38cf8862010-09-26 14:18:51 -07003096 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003097 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003098 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003099 pw.decreaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003100
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003101 pw.println();
3102 pw.println("mObbPathToStateMap:");
3103 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003104 final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
3105 while (maps.hasNext()) {
3106 final Entry<String, ObbState> e = maps.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003107 pw.print(e.getKey());
3108 pw.print(" -> ");
3109 pw.println(e.getValue());
Kenny Rootaf9d6672010-10-08 09:21:39 -07003110 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003111 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003112 }
Kenny Root4161f9b2011-07-13 09:48:33 -07003113
Robert Greenwalt470fd722012-01-18 12:51:15 -08003114 pw.println();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003115 pw.println("mConnection:");
3116 pw.increaseIndent();
Robert Greenwalt470fd722012-01-18 12:51:15 -08003117 mConnector.dump(fd, pw, args);
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003118 pw.decreaseIndent();
Christopher Tate7265abe2014-11-21 13:54:45 -08003119
3120 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
3121
3122 pw.println();
3123 pw.print("Last maintenance: ");
3124 pw.println(sdf.format(new Date(mLastMaintenance)));
Kenny Root38cf8862010-09-26 14:18:51 -07003125 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003126
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003127 /** {@inheritDoc} */
Jeff Sharkey48877892015-03-18 11:27:19 -07003128 @Override
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003129 public void monitor() {
3130 if (mConnector != null) {
3131 mConnector.monitor();
3132 }
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07003133 if (mCryptConnector != null) {
3134 mCryptConnector.monitor();
3135 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003136 }
3137}