blob: 0e158a2e59dc14ca8f134ed3c342c97a78b2df57 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Jeff Sharkey4c099d02015-05-15 13:45:00 -070019import static com.android.internal.util.XmlUtils.readBooleanAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070020import static com.android.internal.util.XmlUtils.readIntAttribute;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070021import static com.android.internal.util.XmlUtils.readLongAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070022import static com.android.internal.util.XmlUtils.readStringAttribute;
Jeff Sharkey4c099d02015-05-15 13:45:00 -070023import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070024import static com.android.internal.util.XmlUtils.writeIntAttribute;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070025import static com.android.internal.util.XmlUtils.writeLongAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070026import static com.android.internal.util.XmlUtils.writeStringAttribute;
27import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
28import static org.xmlpull.v1.XmlPullParser.START_TAG;
29
Jason parks8888c592011-01-20 22:46:41 -060030import android.Manifest;
Jeff Sharkeyef10ee02015-07-05 14:17:27 -070031import android.annotation.Nullable;
Elliott Hughesf839b4f2014-09-26 12:30:47 -070032import android.app.ActivityManagerNative;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -070033import android.app.AppOpsManager;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070034import android.app.IActivityManager;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070035import android.content.BroadcastReceiver;
Kenny Roota02b8b02010-08-05 16:14:17 -070036import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.content.Context;
38import android.content.Intent;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070039import android.content.IntentFilter;
Kenny Roota02b8b02010-08-05 16:14:17 -070040import android.content.ServiceConnection;
Jeff Sharkey275e3e42015-04-24 16:10:32 -070041import android.content.pm.IPackageMoveObserver;
42import android.content.pm.PackageManager;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070043import android.content.pm.ProviderInfo;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070044import android.content.pm.UserInfo;
Elliott Hughesf839b4f2014-09-26 12:30:47 -070045import android.content.res.Configuration;
Kenny Root02c87302010-07-01 08:10:18 -070046import android.content.res.ObbInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.net.Uri;
Kenny Root02c87302010-07-01 08:10:18 -070048import android.os.Binder;
Jeff Sharkey4c099d02015-05-15 13:45:00 -070049import android.os.DropBoxManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070050import android.os.Environment;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070051import android.os.Environment.UserEnvironment;
Jeff Sharkey48877892015-03-18 11:27:19 -070052import android.os.FileUtils;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080053import android.os.Handler;
Dianne Hackbornefa92b22013-05-03 14:11:43 -070054import android.os.HandlerThread;
Kenny Roota02b8b02010-08-05 16:14:17 -070055import android.os.IBinder;
Daniel Sandler5f27ef42010-03-16 15:42:02 -040056import android.os.Looper;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080057import android.os.Message;
Jeff Sharkey9527b222015-06-24 15:24:48 -070058import android.os.Process;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070059import android.os.RemoteCallbackList;
San Mehat4270e1e2010-01-29 05:32:19 -080060import android.os.RemoteException;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -080061import android.os.ServiceManager;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -070062import android.os.SystemClock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070064import android.os.UserHandle;
Emily Bernier92aa5a22014-07-07 10:11:48 -040065import android.os.UserManager;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070066import android.os.storage.DiskInfo;
Kenny Roota02b8b02010-08-05 16:14:17 -070067import android.os.storage.IMountService;
68import android.os.storage.IMountServiceListener;
69import android.os.storage.IMountShutdownObserver;
70import android.os.storage.IObbActionListener;
Svet Ganov6ee871e2015-07-10 14:29:33 -070071import android.os.storage.MountServiceInternal;
72import android.os.storage.MountServiceInternal.ExternalStorageMountPolicy;
Kenny Rootaf9d6672010-10-08 09:21:39 -070073import android.os.storage.OnObbStateChangeListener;
Paul Lawrence46791e72014-04-03 09:10:26 -070074import android.os.storage.StorageManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070075import android.os.storage.StorageResultCode;
Mike Lockwood2f6a3882011-05-09 19:08:06 -070076import android.os.storage.StorageVolume;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070077import android.os.storage.VolumeInfo;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070078import android.os.storage.VolumeRecord;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070079import android.provider.MediaStore;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070080import android.provider.Settings;
Jason parksf7b3cd42011-01-27 09:28:25 -060081import android.text.TextUtils;
Jeff Sharkey1783f142015-04-17 10:52:51 -070082import android.text.format.DateUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -070083import android.util.ArrayMap;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070084import android.util.AtomicFile;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070085import android.util.Log;
San Mehata5078592010-03-25 09:36:54 -070086import android.util.Slog;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070087import android.util.TimeUtils;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070088import android.util.Xml;
Jeff Sharkey48877892015-03-18 11:27:19 -070089
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070090import libcore.io.IoUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -070091import libcore.util.EmptyArray;
Mike Lockwood2f6a3882011-05-09 19:08:06 -070092
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -080093import com.android.internal.annotations.GuardedBy;
94import com.android.internal.annotations.VisibleForTesting;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070095import com.android.internal.app.IMediaContainerService;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070096import com.android.internal.os.SomeArgs;
Jeff Sharkey9527b222015-06-24 15:24:48 -070097import com.android.internal.os.Zygote;
Jeff Sharkey48877892015-03-18 11:27:19 -070098import com.android.internal.util.ArrayUtils;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070099import com.android.internal.util.FastXmlSerializer;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -0700100import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700101import com.android.internal.util.Preconditions;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700102import com.android.server.NativeDaemonConnector.Command;
Jeff Sharkey56cd6462013-06-07 15:09:15 -0700103import com.android.server.NativeDaemonConnector.SensitiveArg;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700104import com.android.server.pm.PackageManagerService;
Kenny Roota02b8b02010-08-05 16:14:17 -0700105
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700106import org.xmlpull.v1.XmlPullParser;
107import org.xmlpull.v1.XmlPullParserException;
108import org.xmlpull.v1.XmlSerializer;
109
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700110import java.io.File;
Kenny Root38cf8862010-09-26 14:18:51 -0700111import java.io.FileDescriptor;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700112import java.io.FileInputStream;
113import java.io.FileNotFoundException;
Christopher Tate7265abe2014-11-21 13:54:45 -0800114import java.io.FileOutputStream;
Kenny Root05105f72010-09-22 17:29:43 -0700115import java.io.IOException;
Kenny Root38cf8862010-09-26 14:18:51 -0700116import java.io.PrintWriter;
Kenny Root3b1abba2010-10-13 15:00:07 -0700117import java.math.BigInteger;
Paul Lawrence8e397362014-01-27 15:22:30 -0800118import java.nio.charset.StandardCharsets;
Kenny Root735de3b2010-09-30 14:11:39 -0700119import java.security.NoSuchAlgorithmException;
Kenny Root3b1abba2010-10-13 15:00:07 -0700120import java.security.spec.InvalidKeySpecException;
121import java.security.spec.KeySpec;
San Mehat22dd86e2010-01-12 12:21:18 -0800122import java.util.ArrayList;
Kenny Roota02b8b02010-08-05 16:14:17 -0700123import java.util.HashMap;
San Mehat6cdd9c02010-02-09 14:45:20 -0800124import java.util.HashSet;
Kenny Root38cf8862010-09-26 14:18:51 -0700125import java.util.Iterator;
Kenny Roota02b8b02010-08-05 16:14:17 -0700126import java.util.LinkedList;
127import java.util.List;
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700128import java.util.Locale;
Kenny Roota02b8b02010-08-05 16:14:17 -0700129import java.util.Map;
Kenny Root38cf8862010-09-26 14:18:51 -0700130import java.util.Map.Entry;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700131import java.util.Objects;
Svet Ganov6ee871e2015-07-10 14:29:33 -0700132import java.util.concurrent.CopyOnWriteArrayList;
Kenny Root51a573c2012-05-17 13:30:28 -0700133import java.util.concurrent.CountDownLatch;
134import java.util.concurrent.TimeUnit;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700135import java.util.concurrent.TimeoutException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136
Kenny Root3b1abba2010-10-13 15:00:07 -0700137import javax.crypto.SecretKey;
138import javax.crypto.SecretKeyFactory;
139import javax.crypto.spec.PBEKeySpec;
140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141/**
Jeff Sharkey48877892015-03-18 11:27:19 -0700142 * Service responsible for various storage media. Connects to {@code vold} to
143 * watch for and manage dynamically added storage, such as SD cards and USB mass
144 * storage. Also decides how storage should be presented to users on the device.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 */
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700146class MountService extends IMountService.Stub
147 implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
Jason parks5af0b912010-11-29 09:05:25 -0600148
Jeff Sharkey48877892015-03-18 11:27:19 -0700149 // TODO: finish enforcing UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA
150
Christopher Tated417d622013-08-19 16:14:25 -0700151 // Static direct instance pointer for the tightly-coupled idle service to use
152 static MountService sSelf = null;
153
Jeff Sharkey56e62932015-03-21 20:41:00 -0700154 public static class Lifecycle extends SystemService {
155 private MountService mMountService;
156
157 public Lifecycle(Context context) {
158 super(context);
159 }
160
161 @Override
162 public void onStart() {
163 mMountService = new MountService(getContext());
164 publishBinderService("mount", mMountService);
165 }
166
167 @Override
168 public void onBootPhase(int phase) {
169 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
170 mMountService.systemReady();
171 }
172 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700173
174 @Override
175 public void onStartUser(int userHandle) {
176 mMountService.onStartUser(userHandle);
177 }
178
179 @Override
180 public void onCleanupUser(int userHandle) {
181 mMountService.onCleanupUser(userHandle);
182 }
Jeff Sharkey56e62932015-03-21 20:41:00 -0700183 }
184
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800185 private static final boolean DEBUG_EVENTS = false;
Kenny Rootb7db2722011-01-25 16:39:35 -0800186 private static final boolean DEBUG_OBB = false;
Kenny Root02c87302010-07-01 08:10:18 -0700187
Kenny Root07714d42011-08-17 17:49:28 -0700188 // Disable this since it messes up long-running cryptfs operations.
189 private static final boolean WATCHDOG_ENABLE = false;
190
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 private static final String TAG = "MountService";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700192
Jeff Sharkey9756d752015-05-14 21:07:42 -0700193 private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700194 private static final String TAG_STORAGE_TRIM = "storage_trim";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195
Kenny Root305bcbf2010-09-03 07:56:38 -0700196 private static final String VOLD_TAG = "VoldConnector";
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700197 private static final String CRYPTD_TAG = "CryptdConnector";
Kenny Root305bcbf2010-09-03 07:56:38 -0700198
Kenny Rootcf0b38c2011-03-22 14:17:59 -0700199 /** Maximum number of ASEC containers allowed to be mounted. */
200 private static final int MAX_CONTAINERS = 250;
201
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700202 /** Magic value sent by MoveTask.cpp */
203 private static final int MOVE_STATUS_COPY_FINISHED = 82;
204
San Mehat4270e1e2010-01-29 05:32:19 -0800205 /*
206 * Internal vold response code constants
207 */
San Mehat22dd86e2010-01-12 12:21:18 -0800208 class VoldResponseCode {
San Mehat4270e1e2010-01-29 05:32:19 -0800209 /*
210 * 100 series - Requestion action was initiated; expect another reply
211 * before proceeding with a new command.
212 */
San Mehat22dd86e2010-01-12 12:21:18 -0800213 public static final int VolumeListResult = 110;
214 public static final int AsecListResult = 111;
San Mehatc1b4ce92010-02-16 17:13:03 -0800215 public static final int StorageUsersListResult = 112;
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700216 public static final int CryptfsGetfieldResult = 113;
San Mehat22dd86e2010-01-12 12:21:18 -0800217
San Mehat4270e1e2010-01-29 05:32:19 -0800218 /*
219 * 200 series - Requestion action has been successfully completed.
220 */
221 public static final int ShareStatusResult = 210;
San Mehat22dd86e2010-01-12 12:21:18 -0800222 public static final int AsecPathResult = 211;
San Mehat4270e1e2010-01-29 05:32:19 -0800223 public static final int ShareEnabledResult = 212;
San Mehat22dd86e2010-01-12 12:21:18 -0800224
San Mehat4270e1e2010-01-29 05:32:19 -0800225 /*
226 * 400 series - Command was accepted, but the requested action
227 * did not take place.
228 */
229 public static final int OpFailedNoMedia = 401;
230 public static final int OpFailedMediaBlank = 402;
231 public static final int OpFailedMediaCorrupt = 403;
232 public static final int OpFailedVolNotMounted = 404;
San Mehatd9709982010-02-18 11:43:03 -0800233 public static final int OpFailedStorageBusy = 405;
San Mehat2d66cef2010-03-23 11:12:52 -0700234 public static final int OpFailedStorageNotFound = 406;
San Mehat4270e1e2010-01-29 05:32:19 -0800235
236 /*
237 * 600 series - Unsolicited broadcasts.
238 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700239 public static final int DISK_CREATED = 640;
240 public static final int DISK_SIZE_CHANGED = 641;
241 public static final int DISK_LABEL_CHANGED = 642;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700242 public static final int DISK_SCANNED = 643;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700243 public static final int DISK_SYS_PATH_CHANGED = 644;
Jeff Sharkey48877892015-03-18 11:27:19 -0700244 public static final int DISK_DESTROYED = 649;
245
246 public static final int VOLUME_CREATED = 650;
247 public static final int VOLUME_STATE_CHANGED = 651;
248 public static final int VOLUME_FS_TYPE_CHANGED = 652;
249 public static final int VOLUME_FS_UUID_CHANGED = 653;
250 public static final int VOLUME_FS_LABEL_CHANGED = 654;
251 public static final int VOLUME_PATH_CHANGED = 655;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700252 public static final int VOLUME_INTERNAL_PATH_CHANGED = 656;
Jeff Sharkey48877892015-03-18 11:27:19 -0700253 public static final int VOLUME_DESTROYED = 659;
Svetoslavf23b64d2013-04-25 14:45:54 -0700254
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700255 public static final int MOVE_STATUS = 660;
Jeff Sharkey9756d752015-05-14 21:07:42 -0700256 public static final int BENCHMARK_RESULT = 661;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700257 public static final int TRIM_RESULT = 662;
San Mehat22dd86e2010-01-12 12:21:18 -0800258 }
259
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700260 private static final int VERSION_INIT = 1;
261 private static final int VERSION_ADD_PRIMARY = 2;
Jeff Sharkeyfced5342015-05-10 14:53:34 -0700262 private static final int VERSION_FIX_PRIMARY = 3;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700263
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700264 private static final String TAG_VOLUMES = "volumes";
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700265 private static final String ATTR_VERSION = "version";
266 private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid";
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700267 private static final String ATTR_FORCE_ADOPTABLE = "forceAdoptable";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700268 private static final String TAG_VOLUME = "volume";
269 private static final String ATTR_TYPE = "type";
270 private static final String ATTR_FS_UUID = "fsUuid";
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700271 private static final String ATTR_PART_GUID = "partGuid";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700272 private static final String ATTR_NICKNAME = "nickname";
273 private static final String ATTR_USER_FLAGS = "userFlags";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700274 private static final String ATTR_CREATED_MILLIS = "createdMillis";
275 private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis";
276 private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700277
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700278 private final AtomicFile mSettingsFile;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700279
Jeff Sharkey48877892015-03-18 11:27:19 -0700280 /**
281 * <em>Never</em> hold the lock while performing downcalls into vold, since
282 * unsolicited events can suddenly appear to update data structures.
283 */
284 private final Object mLock = new Object();
285
286 @GuardedBy("mLock")
287 private int[] mStartedUsers = EmptyArray.INT;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700288
289 /** Map from disk ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700290 @GuardedBy("mLock")
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700291 private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700292 /** Map from volume ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700293 @GuardedBy("mLock")
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700294 private ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
Jeff Sharkey48877892015-03-18 11:27:19 -0700295
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700296 /** Map from UUID to record */
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700297 @GuardedBy("mLock")
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700298 private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>();
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700299 @GuardedBy("mLock")
300 private String mPrimaryStorageUuid;
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700301 @GuardedBy("mLock")
302 private boolean mForceAdoptable;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700303
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700304 /** Map from disk ID to latches */
305 @GuardedBy("mLock")
306 private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
307
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700308 @GuardedBy("mLock")
309 private IPackageMoveObserver mMoveCallback;
310 @GuardedBy("mLock")
311 private String mMoveTargetUuid;
312
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700313 private VolumeInfo findVolumeByIdOrThrow(String id) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700314 synchronized (mLock) {
315 final VolumeInfo vol = mVolumes.get(id);
316 if (vol != null) {
317 return vol;
318 }
319 }
320 throw new IllegalArgumentException("No volume found for ID " + id);
321 }
322
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700323 private String findVolumeIdForPathOrThrow(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700324 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700325 for (int i = 0; i < mVolumes.size(); i++) {
326 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700327 if (vol.path != null && path.startsWith(vol.path)) {
328 return vol.id;
Jeff Sharkey48877892015-03-18 11:27:19 -0700329 }
330 }
331 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700332 throw new IllegalArgumentException("No volume found for path " + path);
Jeff Sharkey48877892015-03-18 11:27:19 -0700333 }
334
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700335 private VolumeRecord findRecordForPath(String path) {
336 synchronized (mLock) {
337 for (int i = 0; i < mVolumes.size(); i++) {
338 final VolumeInfo vol = mVolumes.valueAt(i);
339 if (vol.path != null && path.startsWith(vol.path)) {
340 return mRecords.get(vol.fsUuid);
341 }
342 }
343 }
344 return null;
345 }
346
347 private String scrubPath(String path) {
348 if (path.startsWith(Environment.getDataDirectory().getAbsolutePath())) {
349 return "internal";
350 }
351 final VolumeRecord rec = findRecordForPath(path);
352 if (rec == null || rec.createdMillis == 0) {
353 return "unknown";
354 } else {
355 return "ext:" + (int) ((System.currentTimeMillis() - rec.createdMillis)
356 / DateUtils.WEEK_IN_MILLIS) + "w";
357 }
358 }
359
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700360 private @Nullable VolumeInfo findStorageForUuid(String volumeUuid) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700361 final StorageManager storage = mContext.getSystemService(StorageManager.class);
362 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700363 return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL);
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700364 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
365 return storage.getPrimaryPhysicalVolume();
366 } else {
367 return storage.findEmulatedForPrivate(storage.findVolumeByUuid(volumeUuid));
368 }
369 }
370
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700371 private boolean shouldBenchmark() {
372 final long benchInterval = Settings.Global.getLong(mContext.getContentResolver(),
373 Settings.Global.STORAGE_BENCHMARK_INTERVAL, DateUtils.WEEK_IN_MILLIS);
374 synchronized (mLock) {
375 for (int i = 0; i < mVolumes.size(); i++) {
376 final VolumeInfo vol = mVolumes.valueAt(i);
377 final VolumeRecord rec = mRecords.get(vol.fsUuid);
378 if (vol.isMountedReadable() && rec != null) {
379 final long benchAge = System.currentTimeMillis() - rec.lastBenchMillis;
380 if (benchAge >= benchInterval) {
381 return true;
382 }
383 }
384 }
385 return false;
386 }
387 }
388
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700389 private CountDownLatch findOrCreateDiskScanLatch(String diskId) {
390 synchronized (mLock) {
391 CountDownLatch latch = mDiskScanLatches.get(diskId);
392 if (latch == null) {
393 latch = new CountDownLatch(1);
394 mDiskScanLatches.put(diskId, latch);
395 }
396 return latch;
397 }
398 }
399
Paul Lawrence8e397362014-01-27 15:22:30 -0800400 /** List of crypto types.
401 * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
402 * corresponding commands in CommandListener.cpp */
403 public static final String[] CRYPTO_TYPES
404 = { "password", "default", "pattern", "pin" };
405
Brian Carlstrom7395a8a2014-04-28 22:11:01 -0700406 private final Context mContext;
Brian Carlstromdfad99a2014-05-07 15:21:14 -0700407 private final NativeDaemonConnector mConnector;
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700408 private final NativeDaemonConnector mCryptConnector;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700409
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700410 private volatile boolean mSystemReady = false;
Jeff Sharkey48877892015-03-18 11:27:19 -0700411 private volatile boolean mDaemonConnected = false;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700412
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700413 private PackageManagerService mPms;
414
415 private final Callbacks mCallbacks;
Jeff Sharkey48877892015-03-18 11:27:19 -0700416
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700417 // Two connectors - mConnector & mCryptConnector
418 private final CountDownLatch mConnectedSignal = new CountDownLatch(2);
Jeff Sharkey0be607c2012-11-14 14:39:19 -0800419 private final CountDownLatch mAsecsScanned = new CountDownLatch(1);
Jeff Sharkey48877892015-03-18 11:27:19 -0700420
421 private final Object mUnmountLock = new Object();
422 @GuardedBy("mUnmountLock")
423 private CountDownLatch mUnmountSignal;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800424
San Mehat6cdd9c02010-02-09 14:45:20 -0800425 /**
426 * Private hash of currently mounted secure containers.
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800427 * Used as a lock in methods to manipulate secure containers.
San Mehat6cdd9c02010-02-09 14:45:20 -0800428 */
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800429 final private HashSet<String> mAsecMountSet = new HashSet<String>();
San Mehat6cdd9c02010-02-09 14:45:20 -0800430
Kenny Root02c87302010-07-01 08:10:18 -0700431 /**
Kenny Root3b1abba2010-10-13 15:00:07 -0700432 * The size of the crypto algorithm key in bits for OBB files. Currently
433 * Twofish is used which takes 128-bit keys.
434 */
435 private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
436
437 /**
438 * The number of times to run SHA1 in the PBKDF2 function for OBB files.
439 * 1024 is reasonably secure and not too slow.
440 */
441 private static final int PBKDF2_HASH_ROUNDS = 1024;
442
443 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700444 * Mounted OBB tracking information. Used to track the current state of all
445 * OBBs.
Kenny Root02c87302010-07-01 08:10:18 -0700446 */
Kenny Root735de3b2010-09-30 14:11:39 -0700447 final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700448
449 /** Map from raw paths to {@link ObbState}. */
Kenny Roota02b8b02010-08-05 16:14:17 -0700450 final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
451
Svet Ganov6ee871e2015-07-10 14:29:33 -0700452 // Not guarded by a lock.
453 private final MountServiceInternalImpl mMountServiceInternal = new MountServiceInternalImpl();
454
Kenny Roota02b8b02010-08-05 16:14:17 -0700455 class ObbState implements IBinder.DeathRecipient {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700456 public ObbState(String rawPath, String canonicalPath, int callingUid,
457 IObbActionListener token, int nonce) {
458 this.rawPath = rawPath;
459 this.canonicalPath = canonicalPath.toString();
460
461 final int userId = UserHandle.getUserId(callingUid);
462 this.ownerPath = buildObbPath(canonicalPath, userId, false);
463 this.voldPath = buildObbPath(canonicalPath, userId, true);
464
465 this.ownerGid = UserHandle.getSharedAppGid(callingUid);
Kenny Rootaf9d6672010-10-08 09:21:39 -0700466 this.token = token;
467 this.nonce = nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700468 }
469
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700470 final String rawPath;
471 final String canonicalPath;
472 final String ownerPath;
473 final String voldPath;
Kenny Roota02b8b02010-08-05 16:14:17 -0700474
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700475 final int ownerGid;
Kenny Roota02b8b02010-08-05 16:14:17 -0700476
Kenny Rootaf9d6672010-10-08 09:21:39 -0700477 // Token of remote Binder caller
478 final IObbActionListener token;
479
480 // Identifier to pass back to the token
481 final int nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700482
Kenny Root735de3b2010-09-30 14:11:39 -0700483 public IBinder getBinder() {
484 return token.asBinder();
485 }
486
Kenny Roota02b8b02010-08-05 16:14:17 -0700487 @Override
488 public void binderDied() {
489 ObbAction action = new UnmountObbAction(this, true);
490 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root735de3b2010-09-30 14:11:39 -0700491 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700492
Kenny Root5919ac62010-10-05 09:49:40 -0700493 public void link() throws RemoteException {
494 getBinder().linkToDeath(this, 0);
495 }
496
497 public void unlink() {
Kenny Root735de3b2010-09-30 14:11:39 -0700498 getBinder().unlinkToDeath(this, 0);
Kenny Roota02b8b02010-08-05 16:14:17 -0700499 }
Kenny Root38cf8862010-09-26 14:18:51 -0700500
501 @Override
502 public String toString() {
503 StringBuilder sb = new StringBuilder("ObbState{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700504 sb.append("rawPath=").append(rawPath);
505 sb.append(",canonicalPath=").append(canonicalPath);
506 sb.append(",ownerPath=").append(ownerPath);
507 sb.append(",voldPath=").append(voldPath);
508 sb.append(",ownerGid=").append(ownerGid);
509 sb.append(",token=").append(token);
510 sb.append(",binder=").append(getBinder());
Kenny Root38cf8862010-09-26 14:18:51 -0700511 sb.append('}');
512 return sb.toString();
513 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700514 }
515
516 // OBB Action Handler
517 final private ObbActionHandler mObbActionHandler;
518
519 // OBB action handler messages
520 private static final int OBB_RUN_ACTION = 1;
521 private static final int OBB_MCS_BOUND = 2;
522 private static final int OBB_MCS_UNBIND = 3;
523 private static final int OBB_MCS_RECONNECT = 4;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700524 private static final int OBB_FLUSH_MOUNT_STATE = 5;
Kenny Roota02b8b02010-08-05 16:14:17 -0700525
526 /*
527 * Default Container Service information
528 */
529 static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
530 "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
531
532 final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
533
534 class DefaultContainerConnection implements ServiceConnection {
Jeff Sharkey48877892015-03-18 11:27:19 -0700535 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700536 public void onServiceConnected(ComponentName name, IBinder service) {
537 if (DEBUG_OBB)
538 Slog.i(TAG, "onServiceConnected");
539 IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
540 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
541 }
542
Jeff Sharkey48877892015-03-18 11:27:19 -0700543 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700544 public void onServiceDisconnected(ComponentName name) {
545 if (DEBUG_OBB)
546 Slog.i(TAG, "onServiceDisconnected");
547 }
548 };
549
550 // Used in the ObbActionHandler
551 private IMediaContainerService mContainerService = null;
Kenny Root02c87302010-07-01 08:10:18 -0700552
Christopher Tate7265abe2014-11-21 13:54:45 -0800553 // Last fstrim operation tracking
554 private static final String LAST_FSTRIM_FILE = "last-fstrim";
555 private final File mLastMaintenanceFile;
556 private long mLastMaintenance;
557
Kenny Root02c87302010-07-01 08:10:18 -0700558 // Handler messages
Jeff Sharkey48877892015-03-18 11:27:19 -0700559 private static final int H_SYSTEM_READY = 1;
560 private static final int H_DAEMON_CONNECTED = 2;
561 private static final int H_SHUTDOWN = 3;
562 private static final int H_FSTRIM = 4;
563 private static final int H_VOLUME_MOUNT = 5;
564 private static final int H_VOLUME_BROADCAST = 6;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800565
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400566 class MountServiceHandler extends Handler {
Jeff Sharkey48877892015-03-18 11:27:19 -0700567 public MountServiceHandler(Looper looper) {
568 super(looper);
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400569 }
570
Jason parks5af0b912010-11-29 09:05:25 -0600571 @Override
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800572 public void handleMessage(Message msg) {
573 switch (msg.what) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700574 case H_SYSTEM_READY: {
Jeff Sharkey48877892015-03-18 11:27:19 -0700575 handleSystemReady();
576 break;
577 }
578 case H_DAEMON_CONNECTED: {
579 handleDaemonConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700580 break;
581 }
Christopher Tated417d622013-08-19 16:14:25 -0700582 case H_FSTRIM: {
Jeff Sharkey1783f142015-04-17 10:52:51 -0700583 if (!isReady()) {
584 Slog.i(TAG, "fstrim requested, but no daemon connection yet; trying again");
Christopher Tate7618db12015-04-28 16:32:55 -0700585 sendMessageDelayed(obtainMessage(H_FSTRIM, msg.obj),
586 DateUtils.SECOND_IN_MILLIS);
587 break;
Jeff Sharkey1783f142015-04-17 10:52:51 -0700588 }
589
Christopher Tated417d622013-08-19 16:14:25 -0700590 Slog.i(TAG, "Running fstrim idle maintenance");
Christopher Tate7265abe2014-11-21 13:54:45 -0800591
592 // Remember when we kicked it off
593 try {
594 mLastMaintenance = System.currentTimeMillis();
595 mLastMaintenanceFile.setLastModified(mLastMaintenance);
596 } catch (Exception e) {
597 Slog.e(TAG, "Unable to record last fstrim!");
598 }
599
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700600 final boolean shouldBenchmark = shouldBenchmark();
Christopher Tated417d622013-08-19 16:14:25 -0700601 try {
602 // This method must be run on the main (handler) thread,
603 // so it is safe to directly call into vold.
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700604 mConnector.execute("fstrim", shouldBenchmark ? "dotrimbench" : "dotrim");
Christopher Tated417d622013-08-19 16:14:25 -0700605 } catch (NativeDaemonConnectorException ndce) {
606 Slog.e(TAG, "Failed to run fstrim!");
607 }
Christopher Tate7265abe2014-11-21 13:54:45 -0800608
Christopher Tated417d622013-08-19 16:14:25 -0700609 // invoke the completion callback, if any
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700610 // TODO: fstrim is non-blocking, so remove this useless callback
Christopher Tated417d622013-08-19 16:14:25 -0700611 Runnable callback = (Runnable) msg.obj;
612 if (callback != null) {
613 callback.run();
614 }
615 break;
616 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700617 case H_SHUTDOWN: {
618 final IMountShutdownObserver obs = (IMountShutdownObserver) msg.obj;
619 boolean success = false;
620 try {
621 success = mConnector.execute("volume", "shutdown").isClassOk();
622 } catch (NativeDaemonConnectorException ignored) {
623 }
624 if (obs != null) {
625 try {
626 obs.onShutDownComplete(success ? 0 : -1);
627 } catch (RemoteException ignored) {
628 }
629 }
630 break;
631 }
632 case H_VOLUME_MOUNT: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700633 final VolumeInfo vol = (VolumeInfo) msg.obj;
Jeff Sharkey48877892015-03-18 11:27:19 -0700634 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700635 mConnector.execute("volume", "mount", vol.id, vol.mountFlags,
636 vol.mountUserId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700637 } catch (NativeDaemonConnectorException ignored) {
638 }
639 break;
640 }
641 case H_VOLUME_BROADCAST: {
642 final StorageVolume userVol = (StorageVolume) msg.obj;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700643 final String envState = userVol.getState();
644 Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + envState + " to "
Jeff Sharkey48877892015-03-18 11:27:19 -0700645 + userVol.getOwner());
646
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700647 final String action = VolumeInfo.getBroadcastForEnvironment(envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700648 if (action != null) {
649 final Intent intent = new Intent(action,
650 Uri.fromFile(userVol.getPathFile()));
651 intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, userVol);
652 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
653 mContext.sendBroadcastAsUser(intent, userVol.getOwner());
654 }
655 break;
656 }
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800657 }
658 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700659 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700660
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700661 private final Handler mHandler;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800662
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700663 private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
664 @Override
665 public void onReceive(Context context, Intent intent) {
666 final String action = intent.getAction();
667 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
668
669 try {
670 if (Intent.ACTION_USER_ADDED.equals(action)) {
671 final UserManager um = mContext.getSystemService(UserManager.class);
672 final int userSerialNumber = um.getUserSerialNumber(userId);
673 mConnector.execute("volume", "user_added", userId, userSerialNumber);
674 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
675 mConnector.execute("volume", "user_removed", userId);
676 }
677 } catch (NativeDaemonConnectorException e) {
678 Slog.w(TAG, "Failed to send user details to vold", e);
679 }
680 }
681 };
682
Jeff Sharkey56e62932015-03-21 20:41:00 -0700683 @Override
684 public void waitForAsecScan() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700685 waitForLatch(mAsecsScanned, "mAsecsScanned");
Kenny Root51a573c2012-05-17 13:30:28 -0700686 }
687
San Mehat207e5382010-02-04 20:46:54 -0800688 private void waitForReady() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700689 waitForLatch(mConnectedSignal, "mConnectedSignal");
Kenny Root51a573c2012-05-17 13:30:28 -0700690 }
691
Jeff Sharkey48877892015-03-18 11:27:19 -0700692 private void waitForLatch(CountDownLatch latch, String condition) {
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700693 try {
694 waitForLatch(latch, condition, -1);
695 } catch (TimeoutException ignored) {
696 }
697 }
698
699 private void waitForLatch(CountDownLatch latch, String condition, long timeoutMillis)
700 throws TimeoutException {
701 final long startMillis = SystemClock.elapsedRealtime();
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700702 while (true) {
Kenny Root51a573c2012-05-17 13:30:28 -0700703 try {
704 if (latch.await(5000, TimeUnit.MILLISECONDS)) {
San Mehat207e5382010-02-04 20:46:54 -0800705 return;
Kenny Root51a573c2012-05-17 13:30:28 -0700706 } else {
707 Slog.w(TAG, "Thread " + Thread.currentThread().getName()
Jeff Sharkey48877892015-03-18 11:27:19 -0700708 + " still waiting for " + condition + "...");
San Mehat207e5382010-02-04 20:46:54 -0800709 }
Kenny Root51a573c2012-05-17 13:30:28 -0700710 } catch (InterruptedException e) {
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700711 Slog.w(TAG, "Interrupt while waiting for " + condition);
San Mehat207e5382010-02-04 20:46:54 -0800712 }
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700713 if (timeoutMillis > 0 && SystemClock.elapsedRealtime() > startMillis + timeoutMillis) {
714 throw new TimeoutException("Thread " + Thread.currentThread().getName()
715 + " gave up waiting for " + condition + " after " + timeoutMillis + "ms");
716 }
San Mehat207e5382010-02-04 20:46:54 -0800717 }
San Mehat1f6301e2010-01-07 22:40:27 -0800718 }
Kenny Root02c87302010-07-01 08:10:18 -0700719
Paul Lawrence945490c2014-03-27 16:37:28 +0000720 private boolean isReady() {
721 try {
722 return mConnectedSignal.await(0, TimeUnit.MILLISECONDS);
723 } catch (InterruptedException e) {
724 return false;
725 }
726 }
727
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700728 private void handleSystemReady() {
Jeff Sharkey9527b222015-06-24 15:24:48 -0700729 synchronized (mLock) {
730 resetIfReadyAndConnectedLocked();
731 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700732
Jeff Sharkey48877892015-03-18 11:27:19 -0700733 // Start scheduling nominally-daily fstrim operations
Christopher Tate115afda2014-06-06 19:06:26 -0700734 MountServiceIdler.scheduleIdlePass(mContext);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700735 }
736
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700737 /**
738 * MediaProvider has a ton of code that makes assumptions about storage
739 * paths never changing, so we outright kill them to pick up new state.
740 */
741 @Deprecated
742 private void killMediaProvider() {
743 final ProviderInfo provider = mPms.resolveContentProvider(MediaStore.AUTHORITY, 0,
744 UserHandle.USER_OWNER);
745 if (provider != null) {
746 final IActivityManager am = ActivityManagerNative.getDefault();
747 try {
748 am.killApplicationWithAppId(provider.applicationInfo.packageName,
749 UserHandle.getAppId(provider.applicationInfo.uid), "vold reset");
750 } catch (RemoteException e) {
751 }
752 }
753 }
754
Jeff Sharkey9527b222015-06-24 15:24:48 -0700755 private void resetIfReadyAndConnectedLocked() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700756 Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
757 + ", mDaemonConnected=" + mDaemonConnected);
758 if (mSystemReady && mDaemonConnected) {
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700759 killMediaProvider();
760
Jeff Sharkey48877892015-03-18 11:27:19 -0700761 mDisks.clear();
762 mVolumes.clear();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700763
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700764 // Create a stub volume that represents internal storage
765 final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
Jeff Sharkey5af1835d2015-07-07 17:26:59 -0700766 VolumeInfo.TYPE_PRIVATE, null, null);
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700767 internal.state = VolumeInfo.STATE_MOUNTED;
768 internal.path = Environment.getDataDirectory().getAbsolutePath();
769 mVolumes.put(internal.id, internal);
770
Jeff Sharkey48877892015-03-18 11:27:19 -0700771 try {
772 mConnector.execute("volume", "reset");
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700773
774 // Tell vold about all existing and started users
775 final UserManager um = mContext.getSystemService(UserManager.class);
776 final List<UserInfo> users = um.getUsers();
777 for (UserInfo user : users) {
778 mConnector.execute("volume", "user_added", user.id, user.serialNumber);
779 }
Jeff Sharkey50a05452015-04-29 11:24:52 -0700780 for (int userId : mStartedUsers) {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700781 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey50a05452015-04-29 11:24:52 -0700782 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700783 } catch (NativeDaemonConnectorException e) {
784 Slog.w(TAG, "Failed to reset vold", e);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700785 }
786 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700787 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700788
Jeff Sharkey48877892015-03-18 11:27:19 -0700789 private void onStartUser(int userId) {
790 Slog.d(TAG, "onStartUser " + userId);
791
792 // We purposefully block here to make sure that user-specific
793 // staging area is ready so it's ready for zygote-forked apps to
794 // bind mount against.
795 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700796 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700797 } catch (NativeDaemonConnectorException ignored) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700798 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700799
800 // Record user as started so newly mounted volumes kick off events
801 // correctly, then synthesize events for any already-mounted volumes.
802 synchronized (mVolumes) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700803 for (int i = 0; i < mVolumes.size(); i++) {
804 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700805 if (vol.isVisibleToUser(userId) && vol.isMountedReadable()) {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700806 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey48877892015-03-18 11:27:19 -0700807 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700808
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700809 final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
810 mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700811 }
812 }
813 mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userId);
814 }
815 }
816
817 private void onCleanupUser(int userId) {
818 Slog.d(TAG, "onCleanupUser " + userId);
819
820 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700821 mConnector.execute("volume", "user_stopped", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700822 } catch (NativeDaemonConnectorException ignored) {
823 }
824
825 synchronized (mVolumes) {
826 mStartedUsers = ArrayUtils.removeInt(mStartedUsers, userId);
827 }
828 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700829
Christopher Tated417d622013-08-19 16:14:25 -0700830 void runIdleMaintenance(Runnable callback) {
831 mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
832 }
833
Christopher Tate7265abe2014-11-21 13:54:45 -0800834 // Binder entry point for kicking off an immediate fstrim
835 @Override
836 public void runMaintenance() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700837 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Christopher Tate7265abe2014-11-21 13:54:45 -0800838 runIdleMaintenance(null);
839 }
840
841 @Override
842 public long lastMaintenance() {
843 return mLastMaintenance;
844 }
845
San Mehat4270e1e2010-01-29 05:32:19 -0800846 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800847 * Callback from NativeDaemonConnector
848 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700849 @Override
San Mehat4270e1e2010-01-29 05:32:19 -0800850 public void onDaemonConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700851 mDaemonConnected = true;
852 mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();
853 }
854
855 private void handleDaemonConnected() {
Jeff Sharkey9527b222015-06-24 15:24:48 -0700856 synchronized (mLock) {
857 resetIfReadyAndConnectedLocked();
858 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700859
San Mehat4270e1e2010-01-29 05:32:19 -0800860 /*
Jeff Sharkey48877892015-03-18 11:27:19 -0700861 * Now that we've done our initialization, release
862 * the hounds!
San Mehat4270e1e2010-01-29 05:32:19 -0800863 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700864 mConnectedSignal.countDown();
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700865 if (mConnectedSignal.getCount() != 0) {
866 // More daemons need to connect
867 return;
868 }
Mike Lockwood7fa24aa2011-03-23 14:52:34 -0400869
Jeff Sharkey48877892015-03-18 11:27:19 -0700870 // On an encrypted device we can't see system properties yet, so pull
871 // the system locale out of the mount service.
872 if ("".equals(SystemProperties.get("vold.encrypt_progress"))) {
873 copyLocaleFromMountService();
874 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700875
Jeff Sharkey48877892015-03-18 11:27:19 -0700876 // Let package manager load internal ASECs.
877 mPms.scanAvailableAsecs();
Mike Lockwood7fa24aa2011-03-23 14:52:34 -0400878
Jeff Sharkey48877892015-03-18 11:27:19 -0700879 // Notify people waiting for ASECs to be scanned that it's done.
880 mAsecsScanned.countDown();
San Mehat4270e1e2010-01-29 05:32:19 -0800881 }
882
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700883 private void copyLocaleFromMountService() {
884 String systemLocale;
885 try {
886 systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
887 } catch (RemoteException e) {
888 return;
889 }
890 if (TextUtils.isEmpty(systemLocale)) {
891 return;
892 }
893
894 Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
895 Locale locale = Locale.forLanguageTag(systemLocale);
896 Configuration config = new Configuration();
897 config.setLocale(locale);
898 try {
899 ActivityManagerNative.getDefault().updateConfiguration(config);
900 } catch (RemoteException e) {
901 Slog.e(TAG, "Error setting system locale from mount service", e);
902 }
Elliott Hughes9c33f282014-10-13 12:39:56 -0700903
904 // Temporary workaround for http://b/17945169.
905 Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
Narayan Kamathd30dbb82015-01-15 14:48:15 +0000906 SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700907 }
908
San Mehat4270e1e2010-01-29 05:32:19 -0800909 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800910 * Callback from NativeDaemonConnector
911 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700912 @Override
Dianne Hackborn77b987f2014-02-26 16:20:52 -0800913 public boolean onCheckHoldWakeLock(int code) {
914 return false;
915 }
916
917 /**
918 * Callback from NativeDaemonConnector
919 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700920 @Override
San Mehat4270e1e2010-01-29 05:32:19 -0800921 public boolean onEvent(int code, String raw, String[] cooked) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700922 synchronized (mLock) {
923 return onEventLocked(code, raw, cooked);
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -0800924 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700925 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -0700926
Jeff Sharkey48877892015-03-18 11:27:19 -0700927 private boolean onEventLocked(int code, String raw, String[] cooked) {
928 switch (code) {
929 case VoldResponseCode.DISK_CREATED: {
930 if (cooked.length != 3) break;
931 final String id = cooked[1];
Jeff Sharkey74acbbb2015-04-21 12:14:03 -0700932 int flags = Integer.parseInt(cooked[2]);
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700933 if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false)
934 || mForceAdoptable) {
Jeff Sharkey74acbbb2015-04-21 12:14:03 -0700935 flags |= DiskInfo.FLAG_ADOPTABLE;
936 }
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700937 mDisks.put(id, new DiskInfo(id, flags));
Jeff Sharkey48877892015-03-18 11:27:19 -0700938 break;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -0700939 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700940 case VoldResponseCode.DISK_SIZE_CHANGED: {
941 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700942 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -0700943 if (disk != null) {
944 disk.size = Long.parseLong(cooked[2]);
San Mehat4270e1e2010-01-29 05:32:19 -0800945 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700946 break;
947 }
948 case VoldResponseCode.DISK_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700949 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -0700950 if (disk != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700951 final StringBuilder builder = new StringBuilder();
952 for (int i = 2; i < cooked.length; i++) {
953 builder.append(cooked[i]).append(' ');
954 }
955 disk.label = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -0700956 }
957 break;
958 }
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700959 case VoldResponseCode.DISK_SCANNED: {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700960 if (cooked.length != 2) break;
961 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700962 if (disk != null) {
963 onDiskScannedLocked(disk);
964 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700965 break;
966 }
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700967 case VoldResponseCode.DISK_SYS_PATH_CHANGED: {
968 if (cooked.length != 3) break;
969 final DiskInfo disk = mDisks.get(cooked[1]);
970 if (disk != null) {
971 disk.sysPath = cooked[2];
972 }
973 break;
974 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700975 case VoldResponseCode.DISK_DESTROYED: {
976 if (cooked.length != 2) break;
Makoto Onuki9dc575d2015-06-12 16:10:25 -0700977 final DiskInfo disk = mDisks.remove(cooked[1]);
978 if (disk != null) {
979 mCallbacks.notifyDiskDestroyed(disk);
980 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700981 break;
982 }
San Mehat4270e1e2010-01-29 05:32:19 -0800983
Jeff Sharkey48877892015-03-18 11:27:19 -0700984 case VoldResponseCode.VOLUME_CREATED: {
Jeff Sharkey48877892015-03-18 11:27:19 -0700985 final String id = cooked[1];
986 final int type = Integer.parseInt(cooked[2]);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700987 final String diskId = TextUtils.nullIfEmpty(cooked[3]);
988 final String partGuid = TextUtils.nullIfEmpty(cooked[4]);
989
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700990 final DiskInfo disk = mDisks.get(diskId);
Jeff Sharkey5af1835d2015-07-07 17:26:59 -0700991 final VolumeInfo vol = new VolumeInfo(id, type, disk, partGuid);
Jeff Sharkey48877892015-03-18 11:27:19 -0700992 mVolumes.put(id, vol);
993 onVolumeCreatedLocked(vol);
994 break;
995 }
996 case VoldResponseCode.VOLUME_STATE_CHANGED: {
997 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700998 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -0700999 if (vol != null) {
1000 final int oldState = vol.state;
1001 final int newState = Integer.parseInt(cooked[2]);
1002 vol.state = newState;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001003 onVolumeStateChangedLocked(vol, oldState, newState);
Jeff Sharkey48877892015-03-18 11:27:19 -07001004 }
1005 break;
1006 }
1007 case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: {
1008 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001009 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001010 if (vol != null) {
1011 vol.fsType = cooked[2];
1012 }
1013 break;
1014 }
1015 case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
1016 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001017 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001018 if (vol != null) {
1019 vol.fsUuid = cooked[2];
1020 }
1021 break;
1022 }
1023 case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001024 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001025 if (vol != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001026 final StringBuilder builder = new StringBuilder();
1027 for (int i = 2; i < cooked.length; i++) {
1028 builder.append(cooked[i]).append(' ');
1029 }
1030 vol.fsLabel = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001031 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001032 // TODO: notify listeners that label changed
Jeff Sharkey48877892015-03-18 11:27:19 -07001033 break;
1034 }
1035 case VoldResponseCode.VOLUME_PATH_CHANGED: {
1036 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001037 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001038 if (vol != null) {
1039 vol.path = cooked[2];
1040 }
1041 break;
1042 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001043 case VoldResponseCode.VOLUME_INTERNAL_PATH_CHANGED: {
1044 if (cooked.length != 3) break;
1045 final VolumeInfo vol = mVolumes.get(cooked[1]);
1046 if (vol != null) {
1047 vol.internalPath = cooked[2];
1048 }
1049 break;
1050 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001051 case VoldResponseCode.VOLUME_DESTROYED: {
1052 if (cooked.length != 2) break;
1053 mVolumes.remove(cooked[1]);
1054 break;
1055 }
San Mehat4270e1e2010-01-29 05:32:19 -08001056
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001057 case VoldResponseCode.MOVE_STATUS: {
1058 final int status = Integer.parseInt(cooked[1]);
1059 onMoveStatusLocked(status);
1060 break;
1061 }
Jeff Sharkey9756d752015-05-14 21:07:42 -07001062 case VoldResponseCode.BENCHMARK_RESULT: {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001063 if (cooked.length != 7) break;
1064 final String path = cooked[1];
1065 final String ident = cooked[2];
1066 final long create = Long.parseLong(cooked[3]);
1067 final long drop = Long.parseLong(cooked[4]);
1068 final long run = Long.parseLong(cooked[5]);
1069 final long destroy = Long.parseLong(cooked[6]);
1070
Jeff Sharkey9756d752015-05-14 21:07:42 -07001071 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001072 dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
1073 + " " + ident + " " + create + " " + run + " " + destroy);
1074
1075 final VolumeRecord rec = findRecordForPath(path);
1076 if (rec != null) {
1077 rec.lastBenchMillis = System.currentTimeMillis();
1078 writeSettingsLocked();
1079 }
1080
1081 break;
1082 }
1083 case VoldResponseCode.TRIM_RESULT: {
1084 if (cooked.length != 4) break;
1085 final String path = cooked[1];
1086 final long bytes = Long.parseLong(cooked[2]);
1087 final long time = Long.parseLong(cooked[3]);
1088
1089 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
1090 dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path)
1091 + " " + bytes + " " + time);
1092
1093 final VolumeRecord rec = findRecordForPath(path);
1094 if (rec != null) {
1095 rec.lastTrimMillis = System.currentTimeMillis();
1096 writeSettingsLocked();
1097 }
1098
Jeff Sharkey9756d752015-05-14 21:07:42 -07001099 break;
1100 }
1101
Jeff Sharkey48877892015-03-18 11:27:19 -07001102 default: {
1103 Slog.d(TAG, "Unhandled vold event " + code);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001104 }
San Mehat4270e1e2010-01-29 05:32:19 -08001105 }
1106
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001107 return true;
San Mehat4270e1e2010-01-29 05:32:19 -08001108 }
1109
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001110 private void onDiskScannedLocked(DiskInfo disk) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001111 int volumeCount = 0;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001112 for (int i = 0; i < mVolumes.size(); i++) {
1113 final VolumeInfo vol = mVolumes.valueAt(i);
1114 if (Objects.equals(disk.id, vol.getDiskId())) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001115 volumeCount++;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001116 }
1117 }
1118
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001119 final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
1120 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1121 intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
1122 intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
1123 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
1124 android.Manifest.permission.WRITE_MEDIA_STORAGE);
1125
1126 final CountDownLatch latch = mDiskScanLatches.remove(disk.id);
1127 if (latch != null) {
1128 latch.countDown();
1129 }
1130
Jeff Sharkeyf5a6bd72015-05-19 14:42:38 -07001131 disk.volumeCount = volumeCount;
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001132 mCallbacks.notifyDiskScanned(disk, volumeCount);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001133 }
1134
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001135 private void onVolumeCreatedLocked(VolumeInfo vol) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001136 if (vol.type == VolumeInfo.TYPE_EMULATED) {
1137 final StorageManager storage = mContext.getSystemService(StorageManager.class);
1138 final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
1139
1140 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
1141 && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
1142 Slog.v(TAG, "Found primary storage at " + vol);
1143 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1144 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1145 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1146
1147 } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
1148 Slog.v(TAG, "Found primary storage at " + vol);
1149 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1150 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1151 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1152 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001153
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001154 } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001155 // TODO: only look at first public partition
1156 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1157 && vol.disk.isDefaultPrimary()) {
1158 Slog.v(TAG, "Found primary storage at " + vol);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001159 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1160 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
San Mehat4270e1e2010-01-29 05:32:19 -08001161 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001162
1163 // Adoptable public disks are visible to apps, since they meet
1164 // public API requirement of being in a stable location.
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001165 if (vol.disk.isAdoptable()) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001166 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1167 }
1168
1169 vol.mountUserId = UserHandle.USER_OWNER;
Jeff Sharkey48877892015-03-18 11:27:19 -07001170 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001171
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001172 } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1173 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1174
San Mehat4270e1e2010-01-29 05:32:19 -08001175 } else {
Jeff Sharkey48877892015-03-18 11:27:19 -07001176 Slog.d(TAG, "Skipping automatic mounting of " + vol);
San Mehat4270e1e2010-01-29 05:32:19 -08001177 }
1178 }
1179
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001180 private boolean isBroadcastWorthy(VolumeInfo vol) {
1181 switch (vol.getType()) {
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001182 case VolumeInfo.TYPE_PRIVATE:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001183 case VolumeInfo.TYPE_PUBLIC:
1184 case VolumeInfo.TYPE_EMULATED:
1185 break;
1186 default:
1187 return false;
1188 }
1189
1190 switch (vol.getState()) {
1191 case VolumeInfo.STATE_MOUNTED:
1192 case VolumeInfo.STATE_MOUNTED_READ_ONLY:
1193 case VolumeInfo.STATE_EJECTING:
1194 case VolumeInfo.STATE_UNMOUNTED:
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001195 case VolumeInfo.STATE_UNMOUNTABLE:
Tony Mantlerf0d71052015-06-24 11:45:25 -07001196 case VolumeInfo.STATE_BAD_REMOVAL:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001197 break;
1198 default:
1199 return false;
1200 }
1201
1202 return true;
1203 }
1204
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001205 private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001206 // Remember that we saw this volume so we're ready to accept user
1207 // metadata, or so we can annoy them when a private volume is ejected
1208 if (vol.isMountedReadable() && !TextUtils.isEmpty(vol.fsUuid)) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001209 VolumeRecord rec = mRecords.get(vol.fsUuid);
1210 if (rec == null) {
1211 rec = new VolumeRecord(vol.type, vol.fsUuid);
1212 rec.partGuid = vol.partGuid;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001213 rec.createdMillis = System.currentTimeMillis();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001214 if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1215 rec.nickname = vol.disk.getDescription();
1216 }
1217 mRecords.put(rec.fsUuid, rec);
1218 writeSettingsLocked();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001219 } else {
1220 // Handle upgrade case where we didn't store partition GUID
1221 if (TextUtils.isEmpty(rec.partGuid)) {
1222 rec.partGuid = vol.partGuid;
1223 writeSettingsLocked();
1224 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001225 }
1226 }
1227
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001228 mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
1229
1230 if (isBroadcastWorthy(vol)) {
1231 final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001232 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
1233 intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
Tony Mantlerf0d71052015-06-24 11:45:25 -07001234 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001235 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001236 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
1237 android.Manifest.permission.WRITE_MEDIA_STORAGE);
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001238 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001239
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001240 final String oldStateEnv = VolumeInfo.getEnvironmentForState(oldState);
1241 final String newStateEnv = VolumeInfo.getEnvironmentForState(newState);
Emily Bernier92aa5a22014-07-07 10:11:48 -04001242
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001243 if (!Objects.equals(oldStateEnv, newStateEnv)) {
1244 // Kick state changed event towards all started users. Any users
1245 // started after this point will trigger additional
1246 // user-specific broadcasts.
1247 for (int userId : mStartedUsers) {
1248 if (vol.isVisibleToUser(userId)) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001249 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001250 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey48877892015-03-18 11:27:19 -07001251
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001252 mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
1253 newStateEnv);
San Mehat4270e1e2010-01-29 05:32:19 -08001254 }
1255 }
1256 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001257
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001258 if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.state == VolumeInfo.STATE_EJECTING) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001259 // TODO: this should eventually be handled by new ObbVolume state changes
1260 /*
1261 * Some OBBs might have been unmounted when this volume was
1262 * unmounted, so send a message to the handler to let it know to
1263 * remove those from the list of mounted OBBS.
1264 */
1265 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
1266 OBB_FLUSH_MOUNT_STATE, vol.path));
1267 }
San Mehat4270e1e2010-01-29 05:32:19 -08001268 }
1269
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001270 private void onMoveStatusLocked(int status) {
1271 if (mMoveCallback == null) {
1272 Slog.w(TAG, "Odd, status but no move requested");
1273 return;
1274 }
1275
1276 // TODO: estimate remaining time
1277 try {
Jeff Sharkey50a05452015-04-29 11:24:52 -07001278 mMoveCallback.onStatusChanged(-1, status, -1);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001279 } catch (RemoteException ignored) {
1280 }
1281
1282 // We've finished copying and we're about to clean up old data, so
1283 // remember that move was successful if we get rebooted
1284 if (status == MOVE_STATUS_COPY_FINISHED) {
1285 Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
1286
1287 mPrimaryStorageUuid = mMoveTargetUuid;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001288 writeSettingsLocked();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001289 }
1290
1291 if (PackageManager.isMoveStatusFinished(status)) {
1292 Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status);
1293
1294 mMoveCallback = null;
1295 mMoveTargetUuid = null;
1296 }
1297 }
1298
Jeff Sharkey48877892015-03-18 11:27:19 -07001299 private void enforcePermission(String perm) {
1300 mContext.enforceCallingOrSelfPermission(perm, perm);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001301 }
1302
Jeff Sharkey48877892015-03-18 11:27:19 -07001303 private void enforceUserRestriction(String restriction) {
Emily Bernier92aa5a22014-07-07 10:11:48 -04001304 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
Jeff Sharkey48877892015-03-18 11:27:19 -07001305 if (um.hasUserRestriction(restriction, Binder.getCallingUserHandle())) {
Emily Bernier92aa5a22014-07-07 10:11:48 -04001306 throw new SecurityException("User has restriction " + restriction);
1307 }
1308 }
1309
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001310 private void enforceAdminUser() {
1311 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1312 final int callingUserId = UserHandle.getCallingUserId();
1313 boolean isAdmin;
1314 long token = Binder.clearCallingIdentity();
1315 try {
1316 isAdmin = um.getUserInfo(callingUserId).isAdmin();
1317 } finally {
1318 Binder.restoreCallingIdentity(token);
1319 }
1320 if (!isAdmin) {
1321 throw new SecurityException("Only admin users can adopt sd cards");
1322 }
1323 }
1324
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001325 /**
San Mehat207e5382010-02-04 20:46:54 -08001326 * Constructs a new MountService instance
1327 *
1328 * @param context Binder context for this service
1329 */
1330 public MountService(Context context) {
Christopher Tated417d622013-08-19 16:14:25 -07001331 sSelf = this;
1332
San Mehat207e5382010-02-04 20:46:54 -08001333 mContext = context;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001334 mCallbacks = new Callbacks(FgThread.get().getLooper());
San Mehat207e5382010-02-04 20:46:54 -08001335
San Mehat207e5382010-02-04 20:46:54 -08001336 // XXX: This will go away soon in favor of IMountServiceObserver
1337 mPms = (PackageManagerService) ServiceManager.getService("package");
1338
Dianne Hackbornefa92b22013-05-03 14:11:43 -07001339 HandlerThread hthread = new HandlerThread(TAG);
1340 hthread.start();
1341 mHandler = new MountServiceHandler(hthread.getLooper());
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001342
Kenny Roota02b8b02010-08-05 16:14:17 -07001343 // Add OBB Action Handler to MountService thread.
Dianne Hackborn8d044e82013-04-30 17:24:15 -07001344 mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
Kenny Roota02b8b02010-08-05 16:14:17 -07001345
Christopher Tate7265abe2014-11-21 13:54:45 -08001346 // Initialize the last-fstrim tracking if necessary
1347 File dataDir = Environment.getDataDirectory();
1348 File systemDir = new File(dataDir, "system");
1349 mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
1350 if (!mLastMaintenanceFile.exists()) {
1351 // Not setting mLastMaintenance here means that we will force an
1352 // fstrim during reboot following the OTA that installs this code.
1353 try {
1354 (new FileOutputStream(mLastMaintenanceFile)).close();
1355 } catch (IOException e) {
1356 Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
1357 }
1358 } else {
1359 mLastMaintenance = mLastMaintenanceFile.lastModified();
1360 }
1361
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001362 mSettingsFile = new AtomicFile(
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001363 new File(Environment.getSystemSecureDirectory(), "storage.xml"));
1364
1365 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001366 readSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001367 }
1368
Svet Ganov6ee871e2015-07-10 14:29:33 -07001369 LocalServices.addService(MountServiceInternal.class, mMountServiceInternal);
1370
Marco Nelissenc34ebce2010-02-18 13:39:41 -08001371 /*
Kenny Root305bcbf2010-09-03 07:56:38 -07001372 * Create the connection to vold with a maximum queue of twice the
1373 * amount of containers we'd ever expect to have. This keeps an
1374 * "asec list" from blocking a thread repeatedly.
1375 */
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001376
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001377 mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
1378 null);
Jeff Sharkey48877892015-03-18 11:27:19 -07001379 mConnector.setDebug(true);
Kenny Root51a573c2012-05-17 13:30:28 -07001380
Kenny Root305bcbf2010-09-03 07:56:38 -07001381 Thread thread = new Thread(mConnector, VOLD_TAG);
San Mehat207e5382010-02-04 20:46:54 -08001382 thread.start();
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07001383
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001384 // Reuse parameters from first connector since they are tested and safe
1385 mCryptConnector = new NativeDaemonConnector(this, "cryptd",
1386 MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
1387 mCryptConnector.setDebug(true);
1388
1389 Thread crypt_thread = new Thread(mCryptConnector, CRYPTD_TAG);
1390 crypt_thread.start();
1391
Jeff Sharkeybcd262d2015-06-10 09:41:17 -07001392 final IntentFilter userFilter = new IntentFilter();
1393 userFilter.addAction(Intent.ACTION_USER_ADDED);
1394 userFilter.addAction(Intent.ACTION_USER_REMOVED);
1395 mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
1396
Kenny Root07714d42011-08-17 17:49:28 -07001397 // Add ourself to the Watchdog monitors if enabled.
1398 if (WATCHDOG_ENABLE) {
1399 Watchdog.getInstance().addMonitor(this);
1400 }
San Mehat207e5382010-02-04 20:46:54 -08001401 }
1402
Jeff Sharkey56e62932015-03-21 20:41:00 -07001403 private void systemReady() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001404 mSystemReady = true;
1405 mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
1406 }
1407
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001408 private String getDefaultPrimaryStorageUuid() {
1409 if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) {
1410 return StorageManager.UUID_PRIMARY_PHYSICAL;
1411 } else {
1412 return StorageManager.UUID_PRIVATE_INTERNAL;
1413 }
1414 }
1415
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001416 private void readSettingsLocked() {
1417 mRecords.clear();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001418 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001419 mForceAdoptable = false;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001420
1421 FileInputStream fis = null;
1422 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001423 fis = mSettingsFile.openRead();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001424 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001425 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001426
1427 int type;
1428 while ((type = in.next()) != END_DOCUMENT) {
1429 if (type == START_TAG) {
1430 final String tag = in.getName();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001431 if (TAG_VOLUMES.equals(tag)) {
1432 final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001433 final boolean primaryPhysical = SystemProperties.getBoolean(
1434 StorageManager.PROP_PRIMARY_PHYSICAL, false);
1435 final boolean validAttr = (version >= VERSION_FIX_PRIMARY)
1436 || (version >= VERSION_ADD_PRIMARY && !primaryPhysical);
1437 if (validAttr) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001438 mPrimaryStorageUuid = readStringAttribute(in,
1439 ATTR_PRIMARY_STORAGE_UUID);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001440 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001441 mForceAdoptable = readBooleanAttribute(in, ATTR_FORCE_ADOPTABLE, false);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001442
1443 } else if (TAG_VOLUME.equals(tag)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001444 final VolumeRecord rec = readVolumeRecord(in);
1445 mRecords.put(rec.fsUuid, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001446 }
1447 }
1448 }
1449 } catch (FileNotFoundException e) {
1450 // Missing metadata is okay, probably first boot
1451 } catch (IOException e) {
1452 Slog.wtf(TAG, "Failed reading metadata", e);
1453 } catch (XmlPullParserException e) {
1454 Slog.wtf(TAG, "Failed reading metadata", e);
1455 } finally {
1456 IoUtils.closeQuietly(fis);
1457 }
1458 }
1459
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001460 private void writeSettingsLocked() {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001461 FileOutputStream fos = null;
1462 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001463 fos = mSettingsFile.startWrite();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001464
1465 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001466 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001467 out.startDocument(null, true);
1468 out.startTag(null, TAG_VOLUMES);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001469 writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001470 writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001471 writeBooleanAttribute(out, ATTR_FORCE_ADOPTABLE, mForceAdoptable);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001472 final int size = mRecords.size();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001473 for (int i = 0; i < size; i++) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001474 final VolumeRecord rec = mRecords.valueAt(i);
1475 writeVolumeRecord(out, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001476 }
1477 out.endTag(null, TAG_VOLUMES);
1478 out.endDocument();
1479
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001480 mSettingsFile.finishWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001481 } catch (IOException e) {
1482 if (fos != null) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001483 mSettingsFile.failWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001484 }
1485 }
1486 }
1487
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001488 public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
1489 final int type = readIntAttribute(in, ATTR_TYPE);
1490 final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
1491 final VolumeRecord meta = new VolumeRecord(type, fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001492 meta.partGuid = readStringAttribute(in, ATTR_PART_GUID);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001493 meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
1494 meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001495 meta.createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
1496 meta.lastTrimMillis = readLongAttribute(in, ATTR_LAST_TRIM_MILLIS);
1497 meta.lastBenchMillis = readLongAttribute(in, ATTR_LAST_BENCH_MILLIS);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001498 return meta;
1499 }
1500
1501 public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
1502 out.startTag(null, TAG_VOLUME);
1503 writeIntAttribute(out, ATTR_TYPE, rec.type);
1504 writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001505 writeStringAttribute(out, ATTR_PART_GUID, rec.partGuid);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001506 writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
1507 writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001508 writeLongAttribute(out, ATTR_CREATED_MILLIS, rec.createdMillis);
1509 writeLongAttribute(out, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
1510 writeLongAttribute(out, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001511 out.endTag(null, TAG_VOLUME);
1512 }
1513
San Mehat207e5382010-02-04 20:46:54 -08001514 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001515 * Exposed API calls below here
1516 */
1517
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001518 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001519 public void registerListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001520 mCallbacks.register(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001521 }
1522
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001523 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001524 public void unregisterListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001525 mCallbacks.unregister(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001526 }
1527
Jeff Sharkey48877892015-03-18 11:27:19 -07001528 @Override
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -08001529 public void shutdown(final IMountShutdownObserver observer) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001530 enforcePermission(android.Manifest.permission.SHUTDOWN);
San Mehat4270e1e2010-01-29 05:32:19 -08001531
San Mehata5078592010-03-25 09:36:54 -07001532 Slog.i(TAG, "Shutting down");
Jeff Sharkey48877892015-03-18 11:27:19 -07001533 mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001534 }
1535
Jeff Sharkey48877892015-03-18 11:27:19 -07001536 @Override
San Mehatb1043402010-02-05 08:26:50 -08001537 public boolean isUsbMassStorageConnected() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001538 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001539 }
1540
Jeff Sharkey48877892015-03-18 11:27:19 -07001541 @Override
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -08001542 public void setUsbMassStorageEnabled(boolean enable) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001543 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001544 }
1545
Jeff Sharkey48877892015-03-18 11:27:19 -07001546 @Override
San Mehatb1043402010-02-05 08:26:50 -08001547 public boolean isUsbMassStorageEnabled() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001548 throw new UnsupportedOperationException();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001549 }
Jason parks9ed98bc2011-01-17 09:58:35 -06001550
Jeff Sharkey48877892015-03-18 11:27:19 -07001551 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001552 public String getVolumeState(String mountPoint) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001553 throw new UnsupportedOperationException();
San Mehat7fd0fee2009-12-17 07:12:23 -08001554 }
1555
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001556 @Override
Kenny Roote1ff2142010-10-12 11:20:01 -07001557 public boolean isExternalStorageEmulated() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001558 throw new UnsupportedOperationException();
Kenny Roote1ff2142010-10-12 11:20:01 -07001559 }
1560
Jeff Sharkey48877892015-03-18 11:27:19 -07001561 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001562 public int mountVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001563 mount(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001564 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001565 }
1566
Jeff Sharkey48877892015-03-18 11:27:19 -07001567 @Override
Ben Komalo13c71972011-09-07 16:35:56 -07001568 public void unmountVolume(String path, boolean force, boolean removeEncryption) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001569 unmount(findVolumeIdForPathOrThrow(path));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001570 }
1571
Jeff Sharkey48877892015-03-18 11:27:19 -07001572 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001573 public int formatVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001574 format(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001575 return 0;
1576 }
1577
1578 @Override
1579 public void mount(String volId) {
1580 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1581 waitForReady();
1582
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001583 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001584 if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
1585 enforceUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA);
1586 }
1587 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001588 mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001589 } catch (NativeDaemonConnectorException e) {
1590 throw e.rethrowAsParcelableException();
1591 }
1592 }
1593
1594 @Override
1595 public void unmount(String volId) {
1596 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1597 waitForReady();
1598
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001599 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001600
1601 // TODO: expand PMS to know about multiple volumes
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001602 if (vol.isPrimaryPhysical()) {
1603 final long ident = Binder.clearCallingIdentity();
1604 try {
1605 synchronized (mUnmountLock) {
1606 mUnmountSignal = new CountDownLatch(1);
1607 mPms.updateExternalMediaStatus(false, true);
1608 waitForLatch(mUnmountSignal, "mUnmountSignal");
1609 mUnmountSignal = null;
1610 }
1611 } finally {
1612 Binder.restoreCallingIdentity(ident);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001613 }
1614 }
1615
1616 try {
1617 mConnector.execute("volume", "unmount", vol.id);
1618 } catch (NativeDaemonConnectorException e) {
1619 throw e.rethrowAsParcelableException();
1620 }
1621 }
1622
1623 @Override
1624 public void format(String volId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001625 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -08001626 waitForReady();
San Mehat5b77dab2010-01-26 13:28:50 -08001627
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001628 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001629 try {
Jeff Sharkey4e83cc92015-05-27 14:38:39 -07001630 mConnector.execute("volume", "format", vol.id, "auto");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001631 } catch (NativeDaemonConnectorException e) {
1632 throw e.rethrowAsParcelableException();
Jeff Sharkey48877892015-03-18 11:27:19 -07001633 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001634 }
1635
1636 @Override
Jeff Sharkey9756d752015-05-14 21:07:42 -07001637 public long benchmark(String volId) {
1638 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1639 waitForReady();
1640
1641 try {
Jeff Sharkey14cbe522015-07-08 14:06:37 -07001642 // TODO: make benchmark async so we don't block other commands
1643 final NativeDaemonEvent res = mConnector.execute(3 * DateUtils.MINUTE_IN_MILLIS,
1644 "volume", "benchmark", volId);
Jeff Sharkey9756d752015-05-14 21:07:42 -07001645 return Long.parseLong(res.getMessage());
Todd Kennedy8101ee62015-06-23 13:35:28 -07001646 } catch (NativeDaemonTimeoutException e) {
1647 return Long.MAX_VALUE;
Jeff Sharkey9756d752015-05-14 21:07:42 -07001648 } catch (NativeDaemonConnectorException e) {
1649 throw e.rethrowAsParcelableException();
1650 }
1651 }
1652
1653 @Override
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001654 public void partitionPublic(String diskId) {
1655 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1656 waitForReady();
1657
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001658 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001659 try {
1660 mConnector.execute("volume", "partition", diskId, "public");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001661 waitForLatch(latch, "partitionPublic", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001662 } catch (NativeDaemonConnectorException e) {
1663 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001664 } catch (TimeoutException e) {
1665 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001666 }
1667 }
1668
1669 @Override
1670 public void partitionPrivate(String diskId) {
1671 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001672 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001673 waitForReady();
1674
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001675 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001676 try {
1677 mConnector.execute("volume", "partition", diskId, "private");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001678 waitForLatch(latch, "partitionPrivate", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001679 } catch (NativeDaemonConnectorException e) {
1680 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001681 } catch (TimeoutException e) {
1682 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001683 }
1684 }
1685
1686 @Override
1687 public void partitionMixed(String diskId, int ratio) {
1688 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001689 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001690 waitForReady();
1691
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001692 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001693 try {
1694 mConnector.execute("volume", "partition", diskId, "mixed", ratio);
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001695 waitForLatch(latch, "partitionMixed", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001696 } catch (NativeDaemonConnectorException e) {
1697 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001698 } catch (TimeoutException e) {
1699 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001700 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 }
1702
Jeff Sharkey48877892015-03-18 11:27:19 -07001703 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001704 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001705 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1706 waitForReady();
1707
Jeff Sharkey50a05452015-04-29 11:24:52 -07001708 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001709 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001710 final VolumeRecord rec = mRecords.get(fsUuid);
1711 rec.nickname = nickname;
Jeff Sharkey50a05452015-04-29 11:24:52 -07001712 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001713 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001714 }
1715 }
1716
1717 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001718 public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001719 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1720 waitForReady();
1721
Jeff Sharkey50a05452015-04-29 11:24:52 -07001722 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001723 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001724 final VolumeRecord rec = mRecords.get(fsUuid);
1725 rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001726 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001727 writeSettingsLocked();
1728 }
1729 }
1730
1731 @Override
1732 public void forgetVolume(String fsUuid) {
1733 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1734 waitForReady();
1735
Jeff Sharkey50a05452015-04-29 11:24:52 -07001736 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001737 synchronized (mLock) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001738 final VolumeRecord rec = mRecords.remove(fsUuid);
1739 if (rec != null && !TextUtils.isEmpty(rec.partGuid)) {
1740 forgetPartition(rec.partGuid);
1741 }
1742 mCallbacks.notifyVolumeForgotten(fsUuid);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001743
1744 // If this had been primary storage, revert back to internal and
1745 // reset vold so we bind into new volume into place.
1746 if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001747 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey9527b222015-06-24 15:24:48 -07001748 resetIfReadyAndConnectedLocked();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001749 }
1750
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001751 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001752 }
1753 }
1754
Jeff Sharkey7d2af542015-05-12 15:27:15 -07001755 @Override
1756 public void forgetAllVolumes() {
1757 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1758 waitForReady();
1759
Jeff Sharkey50a05452015-04-29 11:24:52 -07001760 synchronized (mLock) {
1761 for (int i = 0; i < mRecords.size(); i++) {
1762 final String fsUuid = mRecords.keyAt(i);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001763 final VolumeRecord rec = mRecords.valueAt(i);
1764 if (!TextUtils.isEmpty(rec.partGuid)) {
1765 forgetPartition(rec.partGuid);
1766 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001767 mCallbacks.notifyVolumeForgotten(fsUuid);
1768 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001769 mRecords.clear();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001770
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001771 if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)) {
1772 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
1773 }
1774
1775 writeSettingsLocked();
Jeff Sharkey9527b222015-06-24 15:24:48 -07001776 resetIfReadyAndConnectedLocked();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001777 }
1778 }
1779
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001780 private void forgetPartition(String partGuid) {
1781 try {
1782 mConnector.execute("volume", "forget_partition", partGuid);
1783 } catch (NativeDaemonConnectorException e) {
1784 Slog.w(TAG, "Failed to forget key for " + partGuid + ": " + e);
1785 }
1786 }
1787
Svet Ganov6ee871e2015-07-10 14:29:33 -07001788 private void remountUidExternalStorage(int uid, int mode) {
Jeff Sharkey9527b222015-06-24 15:24:48 -07001789 waitForReady();
1790
Svet Ganov6ee871e2015-07-10 14:29:33 -07001791 String modeName = "none";
1792 switch (mode) {
1793 case Zygote.MOUNT_EXTERNAL_DEFAULT: {
1794 modeName = "default";
1795 } break;
1796
1797 case Zygote.MOUNT_EXTERNAL_READ: {
1798 modeName = "read";
1799 } break;
1800
1801 case Zygote.MOUNT_EXTERNAL_WRITE: {
1802 modeName = "write";
1803 } break;
Jeff Sharkey9527b222015-06-24 15:24:48 -07001804 }
1805
1806 try {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001807 mConnector.execute("volume", "remount_uid", uid, modeName);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001808 } catch (NativeDaemonConnectorException e) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001809 Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001810 }
1811 }
1812
1813 @Override
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001814 public void setDebugFlags(int flags, int mask) {
1815 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1816 waitForReady();
1817
1818 synchronized (mLock) {
1819 if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
1820 mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
1821 }
1822
1823 writeSettingsLocked();
Jeff Sharkey9527b222015-06-24 15:24:48 -07001824 resetIfReadyAndConnectedLocked();
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001825 }
1826 }
1827
1828 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001829 public String getPrimaryStorageUuid() {
1830 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1831 waitForReady();
1832
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001833 synchronized (mLock) {
1834 return mPrimaryStorageUuid;
1835 }
1836 }
1837
1838 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001839 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
1840 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1841 waitForReady();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001842
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001843 synchronized (mLock) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001844 if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) {
1845 throw new IllegalArgumentException("Primary storage already at " + volumeUuid);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001846 }
1847
1848 if (mMoveCallback != null) {
1849 throw new IllegalStateException("Move already in progress");
1850 }
1851 mMoveCallback = callback;
1852 mMoveTargetUuid = volumeUuid;
1853
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001854 // When moving to/from primary physical volume, we probably just nuked
1855 // the current storage location, so we have nothing to move.
1856 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1857 || Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
1858 Slog.d(TAG, "Skipping move to/from primary physical");
1859 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
1860 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001861 resetIfReadyAndConnectedLocked();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001862
1863 } else {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001864 final VolumeInfo from = findStorageForUuid(mPrimaryStorageUuid);
1865 final VolumeInfo to = findStorageForUuid(volumeUuid);
1866
1867 if (from == null) {
1868 Slog.w(TAG, "Failing move due to missing from volume " + mPrimaryStorageUuid);
1869 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
1870 return;
1871 } else if (to == null) {
1872 Slog.w(TAG, "Failing move due to missing to volume " + volumeUuid);
1873 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
1874 return;
1875 }
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001876
1877 try {
1878 mConnector.execute("volume", "move_storage", from.id, to.id);
1879 } catch (NativeDaemonConnectorException e) {
1880 throw e.rethrowAsParcelableException();
1881 }
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001882 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001883 }
1884 }
1885
1886 @Override
Mike Lockwoodecedfdc2011-06-08 15:11:59 -07001887 public int[] getStorageUsers(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001888 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehatc1b4ce92010-02-16 17:13:03 -08001889 waitForReady();
1890 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08001891 final String[] r = NativeDaemonEvent.filterMessageList(
1892 mConnector.executeForList("storage", "users", path),
1893 VoldResponseCode.StorageUsersListResult);
1894
San Mehatc1b4ce92010-02-16 17:13:03 -08001895 // FMT: <pid> <process name>
1896 int[] data = new int[r.length];
1897 for (int i = 0; i < r.length; i++) {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08001898 String[] tok = r[i].split(" ");
San Mehatc1b4ce92010-02-16 17:13:03 -08001899 try {
1900 data[i] = Integer.parseInt(tok[0]);
1901 } catch (NumberFormatException nfe) {
San Mehata5078592010-03-25 09:36:54 -07001902 Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
San Mehatc1b4ce92010-02-16 17:13:03 -08001903 return new int[0];
1904 }
1905 }
1906 return data;
1907 } catch (NativeDaemonConnectorException e) {
San Mehata5078592010-03-25 09:36:54 -07001908 Slog.e(TAG, "Failed to retrieve storage users list", e);
San Mehatc1b4ce92010-02-16 17:13:03 -08001909 return new int[0];
1910 }
1911 }
1912
San Mehatb1043402010-02-05 08:26:50 -08001913 private void warnOnNotMounted() {
Jeff Sharkey48877892015-03-18 11:27:19 -07001914 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001915 for (int i = 0; i < mVolumes.size(); i++) {
1916 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001917 if (vol.isPrimary() && vol.isMountedWritable()) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001918 // Cool beans, we have a mounted primary volume
1919 return;
1920 }
Jeff Sharkey32ee8312012-09-30 13:21:31 -07001921 }
San Mehatb1043402010-02-05 08:26:50 -08001922 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001923
1924 Slog.w(TAG, "No primary storage mounted!");
San Mehatb1043402010-02-05 08:26:50 -08001925 }
1926
San Mehat4270e1e2010-01-29 05:32:19 -08001927 public String[] getSecureContainerList() {
Jeff Sharkey48877892015-03-18 11:27:19 -07001928 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08001929 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08001930 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08001931
San Mehat4270e1e2010-01-29 05:32:19 -08001932 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08001933 return NativeDaemonEvent.filterMessageList(
1934 mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
San Mehat4270e1e2010-01-29 05:32:19 -08001935 } catch (NativeDaemonConnectorException e) {
1936 return new String[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001937 }
1938 }
San Mehat36972292010-01-06 11:06:32 -08001939
Kenny Root6dceb882012-04-12 14:23:49 -07001940 public int createSecureContainer(String id, int sizeMb, String fstype, String key,
1941 int ownerUid, boolean external) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001942 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehat207e5382010-02-04 20:46:54 -08001943 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08001944 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08001945
San Mehatb1043402010-02-05 08:26:50 -08001946 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08001947 try {
Jeff Sharkey56cd6462013-06-07 15:09:15 -07001948 mConnector.execute("asec", "create", id, sizeMb, fstype, new SensitiveArg(key),
1949 ownerUid, external ? "1" : "0");
San Mehat4270e1e2010-01-29 05:32:19 -08001950 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08001951 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08001952 }
San Mehata181b212010-02-11 06:50:20 -08001953
1954 if (rc == StorageResultCode.OperationSucceeded) {
1955 synchronized (mAsecMountSet) {
1956 mAsecMountSet.add(id);
1957 }
1958 }
San Mehat4270e1e2010-01-29 05:32:19 -08001959 return rc;
San Mehat36972292010-01-06 11:06:32 -08001960 }
1961
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001962 @Override
1963 public int resizeSecureContainer(String id, int sizeMb, String key) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001964 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07001965 waitForReady();
1966 warnOnNotMounted();
1967
1968 int rc = StorageResultCode.OperationSucceeded;
1969 try {
1970 mConnector.execute("asec", "resize", id, sizeMb, new SensitiveArg(key));
1971 } catch (NativeDaemonConnectorException e) {
1972 rc = StorageResultCode.OperationFailedInternalError;
1973 }
1974 return rc;
1975 }
1976
San Mehat4270e1e2010-01-29 05:32:19 -08001977 public int finalizeSecureContainer(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001978 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehatb1043402010-02-05 08:26:50 -08001979 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08001980
San Mehatb1043402010-02-05 08:26:50 -08001981 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08001982 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08001983 mConnector.execute("asec", "finalize", id);
San Mehata181b212010-02-11 06:50:20 -08001984 /*
1985 * Finalization does a remount, so no need
1986 * to update mAsecMountSet
1987 */
San Mehat4270e1e2010-01-29 05:32:19 -08001988 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08001989 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08001990 }
San Mehat4270e1e2010-01-29 05:32:19 -08001991 return rc;
San Mehat36972292010-01-06 11:06:32 -08001992 }
1993
Kenny Root6dceb882012-04-12 14:23:49 -07001994 public int fixPermissionsSecureContainer(String id, int gid, String filename) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001995 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Kenny Root6dceb882012-04-12 14:23:49 -07001996 warnOnNotMounted();
1997
1998 int rc = StorageResultCode.OperationSucceeded;
1999 try {
2000 mConnector.execute("asec", "fixperms", id, gid, filename);
2001 /*
2002 * Fix permissions does a remount, so no need to update
2003 * mAsecMountSet
2004 */
2005 } catch (NativeDaemonConnectorException e) {
2006 rc = StorageResultCode.OperationFailedInternalError;
2007 }
2008 return rc;
2009 }
2010
San Mehatd9709982010-02-18 11:43:03 -08002011 public int destroySecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002012 enforcePermission(android.Manifest.permission.ASEC_DESTROY);
San Mehat207e5382010-02-04 20:46:54 -08002013 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002014 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002015
Kenny Rootaa485402010-09-14 14:49:41 -07002016 /*
2017 * Force a GC to make sure AssetManagers in other threads of the
2018 * system_server are cleaned up. We have to do this since AssetManager
2019 * instances are kept as a WeakReference and it's possible we have files
2020 * open on the external storage.
2021 */
2022 Runtime.getRuntime().gc();
2023
San Mehatb1043402010-02-05 08:26:50 -08002024 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002025 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002026 final Command cmd = new Command("asec", "destroy", id);
2027 if (force) {
2028 cmd.appendArg("force");
2029 }
2030 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002031 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002032 int code = e.getCode();
2033 if (code == VoldResponseCode.OpFailedStorageBusy) {
2034 rc = StorageResultCode.OperationFailedStorageBusy;
2035 } else {
2036 rc = StorageResultCode.OperationFailedInternalError;
2037 }
San Mehat02735bc2010-01-26 15:18:08 -08002038 }
San Mehata181b212010-02-11 06:50:20 -08002039
2040 if (rc == StorageResultCode.OperationSucceeded) {
2041 synchronized (mAsecMountSet) {
2042 if (mAsecMountSet.contains(id)) {
2043 mAsecMountSet.remove(id);
2044 }
2045 }
2046 }
2047
San Mehat4270e1e2010-01-29 05:32:19 -08002048 return rc;
San Mehat36972292010-01-06 11:06:32 -08002049 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002050
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002051 public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002052 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002053 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002054 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002055
San Mehata181b212010-02-11 06:50:20 -08002056 synchronized (mAsecMountSet) {
2057 if (mAsecMountSet.contains(id)) {
2058 return StorageResultCode.OperationFailedStorageMounted;
2059 }
2060 }
2061
San Mehatb1043402010-02-05 08:26:50 -08002062 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002063 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002064 mConnector.execute("asec", "mount", id, new SensitiveArg(key), ownerUid,
2065 readOnly ? "ro" : "rw");
San Mehat4270e1e2010-01-29 05:32:19 -08002066 } catch (NativeDaemonConnectorException e) {
Kenny Rootf0304622010-03-19 19:20:42 -07002067 int code = e.getCode();
2068 if (code != VoldResponseCode.OpFailedStorageBusy) {
2069 rc = StorageResultCode.OperationFailedInternalError;
2070 }
San Mehat02735bc2010-01-26 15:18:08 -08002071 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002072
2073 if (rc == StorageResultCode.OperationSucceeded) {
2074 synchronized (mAsecMountSet) {
2075 mAsecMountSet.add(id);
2076 }
2077 }
San Mehat4270e1e2010-01-29 05:32:19 -08002078 return rc;
San Mehat36972292010-01-06 11:06:32 -08002079 }
2080
San Mehatd9709982010-02-18 11:43:03 -08002081 public int unmountSecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002082 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002083 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002084 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002085
San Mehat6cdd9c02010-02-09 14:45:20 -08002086 synchronized (mAsecMountSet) {
2087 if (!mAsecMountSet.contains(id)) {
San Mehata181b212010-02-11 06:50:20 -08002088 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehat6cdd9c02010-02-09 14:45:20 -08002089 }
2090 }
2091
Kenny Rootaa485402010-09-14 14:49:41 -07002092 /*
2093 * Force a GC to make sure AssetManagers in other threads of the
2094 * system_server are cleaned up. We have to do this since AssetManager
2095 * instances are kept as a WeakReference and it's possible we have files
2096 * open on the external storage.
2097 */
2098 Runtime.getRuntime().gc();
2099
San Mehatb1043402010-02-05 08:26:50 -08002100 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002101 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002102 final Command cmd = new Command("asec", "unmount", id);
2103 if (force) {
2104 cmd.appendArg("force");
2105 }
2106 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002107 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002108 int code = e.getCode();
2109 if (code == VoldResponseCode.OpFailedStorageBusy) {
2110 rc = StorageResultCode.OperationFailedStorageBusy;
2111 } else {
2112 rc = StorageResultCode.OperationFailedInternalError;
2113 }
San Mehat02735bc2010-01-26 15:18:08 -08002114 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002115
2116 if (rc == StorageResultCode.OperationSucceeded) {
2117 synchronized (mAsecMountSet) {
2118 mAsecMountSet.remove(id);
2119 }
2120 }
San Mehat4270e1e2010-01-29 05:32:19 -08002121 return rc;
San Mehat9dba7092010-01-18 06:47:41 -08002122 }
2123
San Mehat6cdd9c02010-02-09 14:45:20 -08002124 public boolean isSecureContainerMounted(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002125 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat6cdd9c02010-02-09 14:45:20 -08002126 waitForReady();
2127 warnOnNotMounted();
2128
2129 synchronized (mAsecMountSet) {
2130 return mAsecMountSet.contains(id);
2131 }
2132 }
2133
San Mehat4270e1e2010-01-29 05:32:19 -08002134 public int renameSecureContainer(String oldId, String newId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002135 enforcePermission(android.Manifest.permission.ASEC_RENAME);
San Mehat207e5382010-02-04 20:46:54 -08002136 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002137 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002138
San Mehata181b212010-02-11 06:50:20 -08002139 synchronized (mAsecMountSet) {
San Mehat85451ee2010-02-24 08:54:18 -08002140 /*
Jason parks9ed98bc2011-01-17 09:58:35 -06002141 * Because a mounted container has active internal state which cannot be
San Mehat85451ee2010-02-24 08:54:18 -08002142 * changed while active, we must ensure both ids are not currently mounted.
2143 */
2144 if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
San Mehata181b212010-02-11 06:50:20 -08002145 return StorageResultCode.OperationFailedStorageMounted;
2146 }
2147 }
2148
San Mehatb1043402010-02-05 08:26:50 -08002149 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002150 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002151 mConnector.execute("asec", "rename", oldId, newId);
San Mehat4270e1e2010-01-29 05:32:19 -08002152 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002153 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002154 }
San Mehata181b212010-02-11 06:50:20 -08002155
San Mehat4270e1e2010-01-29 05:32:19 -08002156 return rc;
San Mehat45f61042010-01-23 08:12:43 -08002157 }
2158
San Mehat4270e1e2010-01-29 05:32:19 -08002159 public String getSecureContainerPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002160 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002161 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002162 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002163
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002164 final NativeDaemonEvent event;
San Mehat2d66cef2010-03-23 11:12:52 -07002165 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002166 event = mConnector.execute("asec", "path", id);
2167 event.checkCode(VoldResponseCode.AsecPathResult);
2168 return event.getMessage();
San Mehat2d66cef2010-03-23 11:12:52 -07002169 } catch (NativeDaemonConnectorException e) {
2170 int code = e.getCode();
2171 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Fredrik Helmera20c8ef2011-02-09 16:16:10 +01002172 Slog.i(TAG, String.format("Container '%s' not found", id));
2173 return null;
San Mehat22dd86e2010-01-12 12:21:18 -08002174 } else {
San Mehat2d66cef2010-03-23 11:12:52 -07002175 throw new IllegalStateException(String.format("Unexpected response code %d", code));
San Mehat22dd86e2010-01-12 12:21:18 -08002176 }
2177 }
San Mehat22dd86e2010-01-12 12:21:18 -08002178 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002179
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002180 public String getSecureContainerFilesystemPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002181 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002182 waitForReady();
2183 warnOnNotMounted();
2184
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002185 final NativeDaemonEvent event;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002186 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002187 event = mConnector.execute("asec", "fspath", id);
2188 event.checkCode(VoldResponseCode.AsecPathResult);
2189 return event.getMessage();
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002190 } catch (NativeDaemonConnectorException e) {
2191 int code = e.getCode();
2192 if (code == VoldResponseCode.OpFailedStorageNotFound) {
2193 Slog.i(TAG, String.format("Container '%s' not found", id));
2194 return null;
2195 } else {
2196 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2197 }
2198 }
2199 }
2200
Jeff Sharkey48877892015-03-18 11:27:19 -07002201 @Override
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002202 public void finishMediaUpdate() {
Jeff Sharkey9527b222015-06-24 15:24:48 -07002203 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
Rubin Xucd7a0142015-04-17 23:45:27 +01002204 throw new SecurityException("no permission to call finishMediaUpdate()");
2205 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002206 if (mUnmountSignal != null) {
2207 mUnmountSignal.countDown();
2208 } else {
2209 Slog.w(TAG, "Odd, nobody asked to unmount?");
2210 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002211 }
Kenny Root02c87302010-07-01 08:10:18 -07002212
Kenny Roota02b8b02010-08-05 16:14:17 -07002213 private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
2214 if (callerUid == android.os.Process.SYSTEM_UID) {
2215 return true;
2216 }
2217
Kenny Root02c87302010-07-01 08:10:18 -07002218 if (packageName == null) {
2219 return false;
2220 }
2221
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07002222 final int packageUid = mPms.getPackageUid(packageName, UserHandle.getUserId(callerUid));
Kenny Root02c87302010-07-01 08:10:18 -07002223
2224 if (DEBUG_OBB) {
2225 Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
2226 packageUid + ", callerUid = " + callerUid);
2227 }
2228
2229 return callerUid == packageUid;
2230 }
2231
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002232 public String getMountedObbPath(String rawPath) {
2233 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002234
Kenny Root02c87302010-07-01 08:10:18 -07002235 waitForReady();
2236 warnOnNotMounted();
2237
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002238 final ObbState state;
Rubin Xucd7a0142015-04-17 23:45:27 +01002239 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002240 state = mObbPathToStateMap.get(rawPath);
2241 }
2242 if (state == null) {
2243 Slog.w(TAG, "Failed to find OBB mounted at " + rawPath);
2244 return null;
2245 }
2246
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002247 final NativeDaemonEvent event;
Kenny Root02c87302010-07-01 08:10:18 -07002248 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002249 event = mConnector.execute("obb", "path", state.voldPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002250 event.checkCode(VoldResponseCode.AsecPathResult);
2251 return event.getMessage();
Kenny Root02c87302010-07-01 08:10:18 -07002252 } catch (NativeDaemonConnectorException e) {
2253 int code = e.getCode();
2254 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Kenny Roota02b8b02010-08-05 16:14:17 -07002255 return null;
Kenny Root02c87302010-07-01 08:10:18 -07002256 } else {
2257 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2258 }
2259 }
2260 }
2261
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002262 @Override
2263 public boolean isObbMounted(String rawPath) {
2264 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002265 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002266 return mObbPathToStateMap.containsKey(rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002267 }
Kenny Root02c87302010-07-01 08:10:18 -07002268 }
2269
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002270 @Override
2271 public void mountObb(
2272 String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) {
2273 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2274 Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
2275 Preconditions.checkNotNull(token, "token cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002276
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002277 final int callingUid = Binder.getCallingUid();
2278 final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce);
2279 final ObbAction action = new MountObbAction(obbState, key, callingUid);
Kenny Roota02b8b02010-08-05 16:14:17 -07002280 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
2281
2282 if (DEBUG_OBB)
2283 Slog.i(TAG, "Send to OBB handler: " + action.toString());
Kenny Root02c87302010-07-01 08:10:18 -07002284 }
2285
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002286 @Override
2287 public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
2288 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2289
2290 final ObbState existingState;
Rubin Xucd7a0142015-04-17 23:45:27 +01002291 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002292 existingState = mObbPathToStateMap.get(rawPath);
Kenny Rootf1121dc2010-09-29 07:30:53 -07002293 }
2294
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002295 if (existingState != null) {
2296 // TODO: separate state object from request data
2297 final int callingUid = Binder.getCallingUid();
2298 final ObbState newState = new ObbState(
2299 rawPath, existingState.canonicalPath, callingUid, token, nonce);
2300 final ObbAction action = new UnmountObbAction(newState, force);
2301 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root02c87302010-07-01 08:10:18 -07002302
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002303 if (DEBUG_OBB)
2304 Slog.i(TAG, "Send to OBB handler: " + action.toString());
2305 } else {
2306 Slog.w(TAG, "Unknown OBB mount at " + rawPath);
2307 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002308 }
2309
Ben Komalo444eca22011-09-01 15:17:44 -07002310 @Override
2311 public int getEncryptionState() {
2312 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2313 "no permission to access the crypt keeper");
2314
2315 waitForReady();
2316
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002317 final NativeDaemonEvent event;
Ben Komalo444eca22011-09-01 15:17:44 -07002318 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002319 event = mCryptConnector.execute("cryptfs", "cryptocomplete");
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002320 return Integer.parseInt(event.getMessage());
Ben Komalo444eca22011-09-01 15:17:44 -07002321 } catch (NumberFormatException e) {
2322 // Bad result - unexpected.
2323 Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
2324 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2325 } catch (NativeDaemonConnectorException e) {
2326 // Something bad happened.
2327 Slog.w(TAG, "Error in communicating with cryptfs in validating");
2328 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2329 }
2330 }
2331
2332 @Override
Jason parks5af0b912010-11-29 09:05:25 -06002333 public int decryptStorage(String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002334 if (TextUtils.isEmpty(password)) {
2335 throw new IllegalArgumentException("password cannot be empty");
Jason parks5af0b912010-11-29 09:05:25 -06002336 }
2337
Jason parks8888c592011-01-20 22:46:41 -06002338 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2339 "no permission to access the crypt keeper");
Jason parks5af0b912010-11-29 09:05:25 -06002340
2341 waitForReady();
2342
2343 if (DEBUG_EVENTS) {
2344 Slog.i(TAG, "decrypting storage...");
2345 }
2346
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002347 final NativeDaemonEvent event;
Jason parks5af0b912010-11-29 09:05:25 -06002348 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002349 event = mCryptConnector.execute("cryptfs", "checkpw", new SensitiveArg(password));
Jason parks9ed98bc2011-01-17 09:58:35 -06002350
Fredrik Roubertda6aedf2011-12-20 17:34:43 +01002351 final int code = Integer.parseInt(event.getMessage());
Jason parks9ed98bc2011-01-17 09:58:35 -06002352 if (code == 0) {
2353 // Decrypt was successful. Post a delayed message before restarting in order
2354 // to let the UI to clear itself
2355 mHandler.postDelayed(new Runnable() {
2356 public void run() {
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002357 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002358 mCryptConnector.execute("cryptfs", "restart");
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002359 } catch (NativeDaemonConnectorException e) {
2360 Slog.e(TAG, "problem executing in background", e);
2361 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002362 }
Jason parksf7b3cd42011-01-27 09:28:25 -06002363 }, 1000); // 1 second
Jason parks9ed98bc2011-01-17 09:58:35 -06002364 }
2365
2366 return code;
Jason parks5af0b912010-11-29 09:05:25 -06002367 } catch (NativeDaemonConnectorException e) {
2368 // Decryption failed
2369 return e.getCode();
2370 }
Jason parks5af0b912010-11-29 09:05:25 -06002371 }
2372
Paul Lawrence46791e72014-04-03 09:10:26 -07002373 public int encryptStorage(int type, String password) {
2374 if (TextUtils.isEmpty(password) && type != StorageManager.CRYPT_TYPE_DEFAULT) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002375 throw new IllegalArgumentException("password cannot be empty");
Jason parks56aa5322011-01-07 09:01:15 -06002376 }
2377
Jason parks8888c592011-01-20 22:46:41 -06002378 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2379 "no permission to access the crypt keeper");
Jason parks56aa5322011-01-07 09:01:15 -06002380
2381 waitForReady();
2382
2383 if (DEBUG_EVENTS) {
Jason parks8888c592011-01-20 22:46:41 -06002384 Slog.i(TAG, "encrypting storage...");
Jason parks56aa5322011-01-07 09:01:15 -06002385 }
2386
2387 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002388 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace", CRYPTO_TYPES[type],
Paul Lawrence05487612015-06-09 13:35:38 -07002389 new SensitiveArg(password));
Jason parks56aa5322011-01-07 09:01:15 -06002390 } catch (NativeDaemonConnectorException e) {
2391 // Encryption failed
2392 return e.getCode();
2393 }
2394
2395 return 0;
2396 }
2397
Paul Lawrence8e397362014-01-27 15:22:30 -08002398 /** Set the password for encrypting the master key.
2399 * @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
2400 * @param password The password to set.
2401 */
2402 public int changeEncryptionPassword(int type, String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002403 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2404 "no permission to access the crypt keeper");
2405
2406 waitForReady();
2407
2408 if (DEBUG_EVENTS) {
2409 Slog.i(TAG, "changing encryption password...");
2410 }
2411
2412 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002413 NativeDaemonEvent event = mCryptConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type],
Paul Lawrence05487612015-06-09 13:35:38 -07002414 new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002415 return Integer.parseInt(event.getMessage());
Jason parksf7b3cd42011-01-27 09:28:25 -06002416 } catch (NativeDaemonConnectorException e) {
2417 // Encryption failed
2418 return e.getCode();
2419 }
2420 }
2421
Christopher Tate32418be2011-10-10 13:51:12 -07002422 /**
2423 * Validate a user-supplied password string with cryptfs
2424 */
2425 @Override
2426 public int verifyEncryptionPassword(String password) throws RemoteException {
2427 // Only the system process is permitted to validate passwords
2428 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2429 throw new SecurityException("no permission to access the crypt keeper");
2430 }
2431
2432 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2433 "no permission to access the crypt keeper");
2434
2435 if (TextUtils.isEmpty(password)) {
2436 throw new IllegalArgumentException("password cannot be empty");
2437 }
2438
2439 waitForReady();
2440
2441 if (DEBUG_EVENTS) {
2442 Slog.i(TAG, "validating encryption password...");
2443 }
2444
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002445 final NativeDaemonEvent event;
Christopher Tate32418be2011-10-10 13:51:12 -07002446 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002447 event = mCryptConnector.execute("cryptfs", "verifypw", new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002448 Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
2449 return Integer.parseInt(event.getMessage());
Christopher Tate32418be2011-10-10 13:51:12 -07002450 } catch (NativeDaemonConnectorException e) {
2451 // Encryption failed
2452 return e.getCode();
2453 }
2454 }
2455
Paul Lawrence8e397362014-01-27 15:22:30 -08002456 /**
2457 * Get the type of encryption used to encrypt the master key.
2458 * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
2459 */
2460 @Override
Svetoslav16e4a1a2014-09-29 18:16:20 -07002461 public int getPasswordType() {
Paul Lawrence8e397362014-01-27 15:22:30 -08002462
2463 waitForReady();
2464
2465 final NativeDaemonEvent event;
2466 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002467 event = mCryptConnector.execute("cryptfs", "getpwtype");
Paul Lawrence8e397362014-01-27 15:22:30 -08002468 for (int i = 0; i < CRYPTO_TYPES.length; ++i) {
2469 if (CRYPTO_TYPES[i].equals(event.getMessage()))
2470 return i;
2471 }
2472
2473 throw new IllegalStateException("unexpected return from cryptfs");
2474 } catch (NativeDaemonConnectorException e) {
2475 throw e.rethrowAsParcelableException();
2476 }
2477 }
2478
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002479 /**
2480 * Set a field in the crypto header.
2481 * @param field field to set
2482 * @param contents contents to set in field
2483 */
2484 @Override
2485 public void setField(String field, String contents) throws RemoteException {
2486
2487 waitForReady();
2488
2489 final NativeDaemonEvent event;
2490 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002491 event = mCryptConnector.execute("cryptfs", "setfield", field, contents);
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002492 } catch (NativeDaemonConnectorException e) {
2493 throw e.rethrowAsParcelableException();
2494 }
2495 }
2496
2497 /**
2498 * Gets a field from the crypto header.
2499 * @param field field to get
2500 * @return contents of field
2501 */
2502 @Override
2503 public String getField(String field) throws RemoteException {
2504
2505 waitForReady();
2506
2507 final NativeDaemonEvent event;
2508 try {
2509 final String[] contents = NativeDaemonEvent.filterMessageList(
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002510 mCryptConnector.executeForList("cryptfs", "getfield", field),
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002511 VoldResponseCode.CryptfsGetfieldResult);
2512 String result = new String();
2513 for (String content : contents) {
2514 result += content;
2515 }
2516 return result;
2517 } catch (NativeDaemonConnectorException e) {
2518 throw e.rethrowAsParcelableException();
2519 }
2520 }
2521
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002522 @Override
Paul Lawrence945490c2014-03-27 16:37:28 +00002523 public String getPassword() throws RemoteException {
Rubin Xucd7a0142015-04-17 23:45:27 +01002524 mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE,
2525 "only keyguard can retrieve password");
Paul Lawrence945490c2014-03-27 16:37:28 +00002526 if (!isReady()) {
2527 return new String();
2528 }
2529
2530 final NativeDaemonEvent event;
2531 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002532 event = mCryptConnector.execute("cryptfs", "getpw");
Paul Lawrence24063b52015-01-06 13:11:23 -08002533 if ("-1".equals(event.getMessage())) {
2534 // -1 equals no password
2535 return null;
2536 }
Paul Lawrence05487612015-06-09 13:35:38 -07002537 return event.getMessage();
Paul Lawrence945490c2014-03-27 16:37:28 +00002538 } catch (NativeDaemonConnectorException e) {
2539 throw e.rethrowAsParcelableException();
Paul Lawrence24063b52015-01-06 13:11:23 -08002540 } catch (IllegalArgumentException e) {
2541 Slog.e(TAG, "Invalid response to getPassword");
2542 return null;
Paul Lawrence945490c2014-03-27 16:37:28 +00002543 }
2544 }
2545
2546 @Override
2547 public void clearPassword() throws RemoteException {
2548 if (!isReady()) {
2549 return;
2550 }
2551
2552 final NativeDaemonEvent event;
2553 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002554 event = mCryptConnector.execute("cryptfs", "clearpw");
Paul Lawrence945490c2014-03-27 16:37:28 +00002555 } catch (NativeDaemonConnectorException e) {
2556 throw e.rethrowAsParcelableException();
2557 }
2558 }
2559
2560 @Override
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002561 public int mkdirs(String callingPkg, String appPath) {
2562 final int userId = UserHandle.getUserId(Binder.getCallingUid());
2563 final UserEnvironment userEnv = new UserEnvironment(userId);
2564
2565 // Validate that reported package name belongs to caller
2566 final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
2567 Context.APP_OPS_SERVICE);
2568 appOps.checkPackage(Binder.getCallingUid(), callingPkg);
2569
Jeff Sharkey48877892015-03-18 11:27:19 -07002570 File appFile = null;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002571 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07002572 appFile = new File(appPath).getCanonicalFile();
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002573 } catch (IOException e) {
2574 Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
2575 return -1;
2576 }
2577
2578 // Try translating the app path into a vold path, but require that it
2579 // belong to the calling package.
Jeff Sharkey48877892015-03-18 11:27:19 -07002580 if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) ||
2581 FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) ||
2582 FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) {
2583 appPath = appFile.getAbsolutePath();
2584 if (!appPath.endsWith("/")) {
2585 appPath = appPath + "/";
2586 }
2587
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002588 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07002589 mConnector.execute("volume", "mkdirs", appPath);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002590 return 0;
2591 } catch (NativeDaemonConnectorException e) {
2592 return e.getCode();
2593 }
2594 }
2595
Jeff Sharkey48877892015-03-18 11:27:19 -07002596 throw new SecurityException("Invalid mkdirs path: " + appFile);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002597 }
2598
2599 @Override
Svet Ganov6ee871e2015-07-10 14:29:33 -07002600 public StorageVolume[] getVolumeList(int uid, String packageName) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002601 final ArrayList<StorageVolume> res = new ArrayList<>();
Jeff Sharkey48877892015-03-18 11:27:19 -07002602 boolean foundPrimary = false;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002603
Svet Ganov6ee871e2015-07-10 14:29:33 -07002604 final int userId = UserHandle.getUserId(uid);
Svetoslav38c3dbb2015-07-14 11:27:06 -07002605 final boolean reportUnmounted;
2606
2607 final long identity = Binder.clearCallingIdentity();
2608 try {
2609 reportUnmounted = !mMountServiceInternal.hasExternalStorage(
2610 uid, packageName);
2611 } finally {
2612 Binder.restoreCallingIdentity(identity);
2613 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07002614
Jeff Sharkey48877892015-03-18 11:27:19 -07002615 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002616 for (int i = 0; i < mVolumes.size(); i++) {
2617 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey48877892015-03-18 11:27:19 -07002618 if (vol.isVisibleToUser(userId)) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07002619 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
2620 reportUnmounted);
Jeff Sharkey48877892015-03-18 11:27:19 -07002621 if (vol.isPrimary()) {
2622 res.add(0, userVol);
2623 foundPrimary = true;
2624 } else {
2625 res.add(userVol);
2626 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002627 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002628 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002629 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002630
2631 if (!foundPrimary) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002632 Log.w(TAG, "No primary storage defined yet; hacking together a stub");
Jeff Sharkey48877892015-03-18 11:27:19 -07002633
2634 final boolean primaryPhysical = SystemProperties.getBoolean(
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002635 StorageManager.PROP_PRIMARY_PHYSICAL, false);
Jeff Sharkey48877892015-03-18 11:27:19 -07002636
2637 final String id = "stub_primary";
2638 final File path = Environment.getLegacyExternalStorageDirectory();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002639 final String description = mContext.getString(android.R.string.unknownName);
Jeff Sharkey48877892015-03-18 11:27:19 -07002640 final boolean primary = true;
2641 final boolean removable = primaryPhysical;
2642 final boolean emulated = !primaryPhysical;
2643 final long mtpReserveSize = 0L;
2644 final boolean allowMassStorage = false;
2645 final long maxFileSize = 0L;
2646 final UserHandle owner = new UserHandle(userId);
2647 final String uuid = null;
Jeff Sharkey48877892015-03-18 11:27:19 -07002648 final String state = Environment.MEDIA_REMOVED;
2649
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07002650 res.add(0, new StorageVolume(id, StorageVolume.STORAGE_ID_INVALID, path,
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002651 description, primary, removable, emulated, mtpReserveSize,
2652 allowMassStorage, maxFileSize, owner, uuid, state));
Jeff Sharkey48877892015-03-18 11:27:19 -07002653 }
2654
2655 return res.toArray(new StorageVolume[res.size()]);
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002656 }
2657
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002658 @Override
2659 public DiskInfo[] getDisks() {
2660 synchronized (mLock) {
2661 final DiskInfo[] res = new DiskInfo[mDisks.size()];
2662 for (int i = 0; i < mDisks.size(); i++) {
2663 res[i] = mDisks.valueAt(i);
2664 }
2665 return res;
2666 }
2667 }
2668
2669 @Override
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07002670 public VolumeInfo[] getVolumes(int flags) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002671 synchronized (mLock) {
2672 final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
2673 for (int i = 0; i < mVolumes.size(); i++) {
2674 res[i] = mVolumes.valueAt(i);
2675 }
2676 return res;
2677 }
2678 }
2679
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07002680 @Override
2681 public VolumeRecord[] getVolumeRecords(int flags) {
2682 synchronized (mLock) {
2683 final VolumeRecord[] res = new VolumeRecord[mRecords.size()];
2684 for (int i = 0; i < mRecords.size(); i++) {
2685 res[i] = mRecords.valueAt(i);
2686 }
2687 return res;
2688 }
2689 }
2690
Kenny Rootaf9d6672010-10-08 09:21:39 -07002691 private void addObbStateLocked(ObbState obbState) throws RemoteException {
2692 final IBinder binder = obbState.getBinder();
2693 List<ObbState> obbStates = mObbMounts.get(binder);
Kenny Root5919ac62010-10-05 09:49:40 -07002694
Kenny Rootaf9d6672010-10-08 09:21:39 -07002695 if (obbStates == null) {
2696 obbStates = new ArrayList<ObbState>();
2697 mObbMounts.put(binder, obbStates);
2698 } else {
2699 for (final ObbState o : obbStates) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002700 if (o.rawPath.equals(obbState.rawPath)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07002701 throw new IllegalStateException("Attempt to add ObbState twice. "
2702 + "This indicates an error in the MountService logic.");
Kenny Root5919ac62010-10-05 09:49:40 -07002703 }
2704 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002705 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07002706
2707 obbStates.add(obbState);
2708 try {
2709 obbState.link();
2710 } catch (RemoteException e) {
2711 /*
2712 * The binder died before we could link it, so clean up our state
2713 * and return failure.
2714 */
2715 obbStates.remove(obbState);
2716 if (obbStates.isEmpty()) {
2717 mObbMounts.remove(binder);
2718 }
2719
2720 // Rethrow the error so mountObb can get it
2721 throw e;
2722 }
2723
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002724 mObbPathToStateMap.put(obbState.rawPath, obbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07002725 }
2726
Kenny Rootaf9d6672010-10-08 09:21:39 -07002727 private void removeObbStateLocked(ObbState obbState) {
2728 final IBinder binder = obbState.getBinder();
2729 final List<ObbState> obbStates = mObbMounts.get(binder);
2730 if (obbStates != null) {
2731 if (obbStates.remove(obbState)) {
2732 obbState.unlink();
Kenny Root05105f72010-09-22 17:29:43 -07002733 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07002734 if (obbStates.isEmpty()) {
2735 mObbMounts.remove(binder);
2736 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002737 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002738
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002739 mObbPathToStateMap.remove(obbState.rawPath);
Kenny Root38cf8862010-09-26 14:18:51 -07002740 }
2741
Kenny Roota02b8b02010-08-05 16:14:17 -07002742 private class ObbActionHandler extends Handler {
2743 private boolean mBound = false;
Kenny Root480afe72010-10-07 10:17:50 -07002744 private final List<ObbAction> mActions = new LinkedList<ObbAction>();
Kenny Roota02b8b02010-08-05 16:14:17 -07002745
2746 ObbActionHandler(Looper l) {
2747 super(l);
2748 }
2749
2750 @Override
2751 public void handleMessage(Message msg) {
2752 switch (msg.what) {
2753 case OBB_RUN_ACTION: {
Kenny Root480afe72010-10-07 10:17:50 -07002754 final ObbAction action = (ObbAction) msg.obj;
Kenny Roota02b8b02010-08-05 16:14:17 -07002755
2756 if (DEBUG_OBB)
2757 Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
2758
2759 // If a bind was already initiated we don't really
2760 // need to do anything. The pending install
2761 // will be processed later on.
2762 if (!mBound) {
2763 // If this is the only one pending we might
2764 // have to bind to the service again.
2765 if (!connectToService()) {
2766 Slog.e(TAG, "Failed to bind to media container service");
2767 action.handleError();
2768 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07002769 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002770 }
Kenny Root735de3b2010-09-30 14:11:39 -07002771
Kenny Root735de3b2010-09-30 14:11:39 -07002772 mActions.add(action);
Kenny Roota02b8b02010-08-05 16:14:17 -07002773 break;
2774 }
2775 case OBB_MCS_BOUND: {
2776 if (DEBUG_OBB)
2777 Slog.i(TAG, "OBB_MCS_BOUND");
2778 if (msg.obj != null) {
2779 mContainerService = (IMediaContainerService) msg.obj;
2780 }
2781 if (mContainerService == null) {
2782 // Something seriously wrong. Bail out
2783 Slog.e(TAG, "Cannot bind to media container service");
2784 for (ObbAction action : mActions) {
2785 // Indicate service bind error
2786 action.handleError();
2787 }
2788 mActions.clear();
2789 } else if (mActions.size() > 0) {
Kenny Root480afe72010-10-07 10:17:50 -07002790 final ObbAction action = mActions.get(0);
Kenny Roota02b8b02010-08-05 16:14:17 -07002791 if (action != null) {
2792 action.execute(this);
2793 }
2794 } else {
2795 // Should never happen ideally.
2796 Slog.w(TAG, "Empty queue");
2797 }
2798 break;
2799 }
2800 case OBB_MCS_RECONNECT: {
2801 if (DEBUG_OBB)
2802 Slog.i(TAG, "OBB_MCS_RECONNECT");
2803 if (mActions.size() > 0) {
2804 if (mBound) {
2805 disconnectService();
2806 }
2807 if (!connectToService()) {
2808 Slog.e(TAG, "Failed to bind to media container service");
2809 for (ObbAction action : mActions) {
2810 // Indicate service bind error
2811 action.handleError();
2812 }
2813 mActions.clear();
2814 }
2815 }
2816 break;
2817 }
2818 case OBB_MCS_UNBIND: {
2819 if (DEBUG_OBB)
2820 Slog.i(TAG, "OBB_MCS_UNBIND");
2821
2822 // Delete pending install
2823 if (mActions.size() > 0) {
2824 mActions.remove(0);
2825 }
2826 if (mActions.size() == 0) {
2827 if (mBound) {
2828 disconnectService();
2829 }
2830 } else {
2831 // There are more pending requests in queue.
2832 // Just post MCS_BOUND message to trigger processing
2833 // of next pending install.
2834 mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
2835 }
2836 break;
2837 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07002838 case OBB_FLUSH_MOUNT_STATE: {
2839 final String path = (String) msg.obj;
2840
2841 if (DEBUG_OBB)
2842 Slog.i(TAG, "Flushing all OBB state for path " + path);
2843
2844 synchronized (mObbMounts) {
2845 final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
2846
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002847 final Iterator<ObbState> i = mObbPathToStateMap.values().iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07002848 while (i.hasNext()) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002849 final ObbState state = i.next();
Kenny Rootaf9d6672010-10-08 09:21:39 -07002850
2851 /*
2852 * If this entry's source file is in the volume path
2853 * that got unmounted, remove it because it's no
2854 * longer valid.
2855 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002856 if (state.canonicalPath.startsWith(path)) {
2857 obbStatesToRemove.add(state);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002858 }
2859 }
2860
2861 for (final ObbState obbState : obbStatesToRemove) {
2862 if (DEBUG_OBB)
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002863 Slog.i(TAG, "Removing state for " + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002864
2865 removeObbStateLocked(obbState);
2866
2867 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002868 obbState.token.onObbResult(obbState.rawPath, obbState.nonce,
Kenny Rootaf9d6672010-10-08 09:21:39 -07002869 OnObbStateChangeListener.UNMOUNTED);
2870 } catch (RemoteException e) {
2871 Slog.i(TAG, "Couldn't send unmount notification for OBB: "
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002872 + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002873 }
2874 }
2875 }
2876 break;
2877 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002878 }
2879 }
2880
2881 private boolean connectToService() {
2882 if (DEBUG_OBB)
2883 Slog.i(TAG, "Trying to bind to DefaultContainerService");
2884
2885 Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Jeff Sharkey6dce4962015-07-03 18:08:41 -07002886 if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE,
2887 UserHandle.OWNER)) {
Kenny Roota02b8b02010-08-05 16:14:17 -07002888 mBound = true;
2889 return true;
2890 }
2891 return false;
2892 }
2893
2894 private void disconnectService() {
2895 mContainerService = null;
2896 mBound = false;
2897 mContext.unbindService(mDefContainerConn);
2898 }
2899 }
2900
2901 abstract class ObbAction {
2902 private static final int MAX_RETRIES = 3;
2903 private int mRetries;
2904
2905 ObbState mObbState;
2906
2907 ObbAction(ObbState obbState) {
2908 mObbState = obbState;
2909 }
2910
2911 public void execute(ObbActionHandler handler) {
2912 try {
2913 if (DEBUG_OBB)
Ben Komalo444eca22011-09-01 15:17:44 -07002914 Slog.i(TAG, "Starting to execute action: " + toString());
Kenny Roota02b8b02010-08-05 16:14:17 -07002915 mRetries++;
2916 if (mRetries > MAX_RETRIES) {
2917 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
Kenny Root480afe72010-10-07 10:17:50 -07002918 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07002919 handleError();
2920 return;
2921 } else {
2922 handleExecute();
2923 if (DEBUG_OBB)
2924 Slog.i(TAG, "Posting install MCS_UNBIND");
2925 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
2926 }
2927 } catch (RemoteException e) {
2928 if (DEBUG_OBB)
2929 Slog.i(TAG, "Posting install MCS_RECONNECT");
2930 mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
2931 } catch (Exception e) {
2932 if (DEBUG_OBB)
2933 Slog.d(TAG, "Error handling OBB action", e);
2934 handleError();
Kenny Root17eb6fb2010-10-06 15:02:52 -07002935 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07002936 }
2937 }
2938
Kenny Root05105f72010-09-22 17:29:43 -07002939 abstract void handleExecute() throws RemoteException, IOException;
Kenny Roota02b8b02010-08-05 16:14:17 -07002940 abstract void handleError();
Kenny Root38cf8862010-09-26 14:18:51 -07002941
2942 protected ObbInfo getObbInfo() throws IOException {
2943 ObbInfo obbInfo;
2944 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002945 obbInfo = mContainerService.getObbInfo(mObbState.ownerPath);
Kenny Root38cf8862010-09-26 14:18:51 -07002946 } catch (RemoteException e) {
2947 Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002948 + mObbState.ownerPath);
Kenny Root38cf8862010-09-26 14:18:51 -07002949 obbInfo = null;
2950 }
2951 if (obbInfo == null) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002952 throw new IOException("Couldn't read OBB file: " + mObbState.ownerPath);
Kenny Root38cf8862010-09-26 14:18:51 -07002953 }
2954 return obbInfo;
2955 }
2956
Kenny Rootaf9d6672010-10-08 09:21:39 -07002957 protected void sendNewStatusOrIgnore(int status) {
2958 if (mObbState == null || mObbState.token == null) {
2959 return;
2960 }
2961
Kenny Root38cf8862010-09-26 14:18:51 -07002962 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002963 mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
Kenny Root38cf8862010-09-26 14:18:51 -07002964 } catch (RemoteException e) {
2965 Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
2966 }
2967 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002968 }
2969
2970 class MountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07002971 private final String mKey;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002972 private final int mCallingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07002973
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002974 MountObbAction(ObbState obbState, String key, int callingUid) {
Kenny Roota02b8b02010-08-05 16:14:17 -07002975 super(obbState);
2976 mKey = key;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002977 mCallingUid = callingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07002978 }
2979
Jason parks5af0b912010-11-29 09:05:25 -06002980 @Override
Kenny Root735de3b2010-09-30 14:11:39 -07002981 public void handleExecute() throws IOException, RemoteException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07002982 waitForReady();
2983 warnOnNotMounted();
2984
Kenny Root38cf8862010-09-26 14:18:51 -07002985 final ObbInfo obbInfo = getObbInfo();
2986
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002987 if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07002988 Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
2989 + " which is owned by " + obbInfo.packageName);
2990 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
2991 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07002992 }
2993
Kenny Rootaf9d6672010-10-08 09:21:39 -07002994 final boolean isMounted;
2995 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002996 isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002997 }
2998 if (isMounted) {
2999 Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
3000 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
3001 return;
3002 }
3003
Kenny Rootaf9d6672010-10-08 09:21:39 -07003004 final String hashedKey;
3005 if (mKey == null) {
3006 hashedKey = "none";
3007 } else {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003008 try {
Kenny Root3b1abba2010-10-13 15:00:07 -07003009 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
3010
3011 KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
3012 PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
3013 SecretKey key = factory.generateSecret(ks);
3014 BigInteger bi = new BigInteger(key.getEncoded());
3015 hashedKey = bi.toString(16);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003016 } catch (NoSuchAlgorithmException e) {
Kenny Root3b1abba2010-10-13 15:00:07 -07003017 Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
3018 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
3019 return;
3020 } catch (InvalidKeySpecException e) {
3021 Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
3022 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root38cf8862010-09-26 14:18:51 -07003023 return;
3024 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003025 }
Kenny Root38cf8862010-09-26 14:18:51 -07003026
Kenny Rootaf9d6672010-10-08 09:21:39 -07003027 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003028 try {
Jeff Sharkey56cd6462013-06-07 15:09:15 -07003029 mConnector.execute("obb", "mount", mObbState.voldPath, new SensitiveArg(hashedKey),
3030 mObbState.ownerGid);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003031 } catch (NativeDaemonConnectorException e) {
3032 int code = e.getCode();
3033 if (code != VoldResponseCode.OpFailedStorageBusy) {
3034 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003035 }
3036 }
3037
Kenny Rootaf9d6672010-10-08 09:21:39 -07003038 if (rc == StorageResultCode.OperationSucceeded) {
3039 if (DEBUG_OBB)
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003040 Slog.d(TAG, "Successfully mounted OBB " + mObbState.voldPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003041
3042 synchronized (mObbMounts) {
3043 addObbStateLocked(mObbState);
3044 }
3045
3046 sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
Kenny Root02c87302010-07-01 08:10:18 -07003047 } else {
Kenny Root05105f72010-09-22 17:29:43 -07003048 Slog.e(TAG, "Couldn't mount OBB file: " + rc);
Kenny Roota02b8b02010-08-05 16:14:17 -07003049
Kenny Rootaf9d6672010-10-08 09:21:39 -07003050 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
Kenny Root02c87302010-07-01 08:10:18 -07003051 }
3052 }
3053
Jason parks5af0b912010-11-29 09:05:25 -06003054 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003055 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003056 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root02c87302010-07-01 08:10:18 -07003057 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003058
3059 @Override
3060 public String toString() {
3061 StringBuilder sb = new StringBuilder();
3062 sb.append("MountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003063 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003064 sb.append('}');
3065 return sb.toString();
3066 }
3067 }
3068
3069 class UnmountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003070 private final boolean mForceUnmount;
Kenny Roota02b8b02010-08-05 16:14:17 -07003071
3072 UnmountObbAction(ObbState obbState, boolean force) {
3073 super(obbState);
3074 mForceUnmount = force;
3075 }
3076
Jason parks5af0b912010-11-29 09:05:25 -06003077 @Override
Kenny Root38cf8862010-09-26 14:18:51 -07003078 public void handleExecute() throws IOException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003079 waitForReady();
3080 warnOnNotMounted();
3081
Kenny Root38cf8862010-09-26 14:18:51 -07003082 final ObbInfo obbInfo = getObbInfo();
Kenny Roota02b8b02010-08-05 16:14:17 -07003083
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003084 final ObbState existingState;
Kenny Root38cf8862010-09-26 14:18:51 -07003085 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003086 existingState = mObbPathToStateMap.get(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003087 }
Kenny Root38cf8862010-09-26 14:18:51 -07003088
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003089 if (existingState == null) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003090 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
3091 return;
3092 }
3093
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003094 if (existingState.ownerGid != mObbState.ownerGid) {
3095 Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
3096 + " (owned by GID " + existingState.ownerGid + ")");
Kenny Rootaf9d6672010-10-08 09:21:39 -07003097 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3098 return;
3099 }
3100
Kenny Rootaf9d6672010-10-08 09:21:39 -07003101 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003102 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003103 final Command cmd = new Command("obb", "unmount", mObbState.voldPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08003104 if (mForceUnmount) {
3105 cmd.appendArg("force");
3106 }
3107 mConnector.execute(cmd);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003108 } catch (NativeDaemonConnectorException e) {
3109 int code = e.getCode();
3110 if (code == VoldResponseCode.OpFailedStorageBusy) {
3111 rc = StorageResultCode.OperationFailedStorageBusy;
3112 } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
3113 // If it's not mounted then we've already won.
3114 rc = StorageResultCode.OperationSucceeded;
3115 } else {
3116 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003117 }
3118 }
3119
Kenny Rootaf9d6672010-10-08 09:21:39 -07003120 if (rc == StorageResultCode.OperationSucceeded) {
3121 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003122 removeObbStateLocked(existingState);
Kenny Root38cf8862010-09-26 14:18:51 -07003123 }
3124
Kenny Rootaf9d6672010-10-08 09:21:39 -07003125 sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
Kenny Roota02b8b02010-08-05 16:14:17 -07003126 } else {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003127 Slog.w(TAG, "Could not unmount OBB: " + existingState);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003128 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
Kenny Roota02b8b02010-08-05 16:14:17 -07003129 }
3130 }
3131
Jason parks5af0b912010-11-29 09:05:25 -06003132 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003133 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003134 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Roota02b8b02010-08-05 16:14:17 -07003135 }
3136
3137 @Override
3138 public String toString() {
3139 StringBuilder sb = new StringBuilder();
3140 sb.append("UnmountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003141 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003142 sb.append(",force=");
3143 sb.append(mForceUnmount);
Kenny Roota02b8b02010-08-05 16:14:17 -07003144 sb.append('}');
3145 return sb.toString();
3146 }
Kenny Root02c87302010-07-01 08:10:18 -07003147 }
Kenny Root38cf8862010-09-26 14:18:51 -07003148
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -08003149 @VisibleForTesting
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003150 public static String buildObbPath(final String canonicalPath, int userId, boolean forVold) {
3151 // TODO: allow caller to provide Environment for full testing
Jeff Sharkey1abdb712013-08-11 16:28:14 -07003152 // TODO: extend to support OBB mounts on secondary external storage
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003153
3154 // Only adjust paths when storage is emulated
3155 if (!Environment.isExternalStorageEmulated()) {
3156 return canonicalPath;
3157 }
3158
3159 String path = canonicalPath.toString();
3160
3161 // First trim off any external storage prefix
3162 final UserEnvironment userEnv = new UserEnvironment(userId);
3163
3164 // /storage/emulated/0
Jeff Sharkey1abdb712013-08-11 16:28:14 -07003165 final String externalPath = userEnv.getExternalStorageDirectory().getAbsolutePath();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003166 // /storage/emulated_legacy
3167 final String legacyExternalPath = Environment.getLegacyExternalStorageDirectory()
Jeff Sharkey1abdb712013-08-11 16:28:14 -07003168 .getAbsolutePath();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003169
3170 if (path.startsWith(externalPath)) {
3171 path = path.substring(externalPath.length() + 1);
3172 } else if (path.startsWith(legacyExternalPath)) {
3173 path = path.substring(legacyExternalPath.length() + 1);
3174 } else {
3175 return canonicalPath;
3176 }
3177
3178 // Handle special OBB paths on emulated storage
3179 final String obbPath = "Android/obb";
3180 if (path.startsWith(obbPath)) {
3181 path = path.substring(obbPath.length() + 1);
3182
Jeff Sharkey48877892015-03-18 11:27:19 -07003183 final UserEnvironment ownerEnv = new UserEnvironment(UserHandle.USER_OWNER);
3184 return new File(ownerEnv.buildExternalStorageAndroidObbDirs()[0], path)
3185 .getAbsolutePath();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003186 }
3187
3188 // Handle normal external storage paths
Jeff Sharkey48877892015-03-18 11:27:19 -07003189 return new File(userEnv.getExternalStorageDirectory(), path).getAbsolutePath();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003190 }
3191
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003192 private static class Callbacks extends Handler {
3193 private static final int MSG_STORAGE_STATE_CHANGED = 1;
3194 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003195 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
3196 private static final int MSG_VOLUME_FORGOTTEN = 4;
3197 private static final int MSG_DISK_SCANNED = 5;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003198 private static final int MSG_DISK_DESTROYED = 6;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003199
3200 private final RemoteCallbackList<IMountServiceListener>
3201 mCallbacks = new RemoteCallbackList<>();
3202
3203 public Callbacks(Looper looper) {
3204 super(looper);
3205 }
3206
3207 public void register(IMountServiceListener callback) {
3208 mCallbacks.register(callback);
3209 }
3210
3211 public void unregister(IMountServiceListener callback) {
3212 mCallbacks.unregister(callback);
3213 }
3214
3215 @Override
3216 public void handleMessage(Message msg) {
3217 final SomeArgs args = (SomeArgs) msg.obj;
3218 final int n = mCallbacks.beginBroadcast();
3219 for (int i = 0; i < n; i++) {
3220 final IMountServiceListener callback = mCallbacks.getBroadcastItem(i);
3221 try {
3222 invokeCallback(callback, msg.what, args);
3223 } catch (RemoteException ignored) {
3224 }
3225 }
3226 mCallbacks.finishBroadcast();
3227 args.recycle();
3228 }
3229
3230 private void invokeCallback(IMountServiceListener callback, int what, SomeArgs args)
3231 throws RemoteException {
3232 switch (what) {
3233 case MSG_STORAGE_STATE_CHANGED: {
3234 callback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
3235 (String) args.arg3);
3236 break;
3237 }
3238 case MSG_VOLUME_STATE_CHANGED: {
3239 callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
3240 break;
3241 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07003242 case MSG_VOLUME_RECORD_CHANGED: {
3243 callback.onVolumeRecordChanged((VolumeRecord) args.arg1);
3244 break;
3245 }
3246 case MSG_VOLUME_FORGOTTEN: {
3247 callback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003248 break;
3249 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003250 case MSG_DISK_SCANNED: {
3251 callback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003252 break;
3253 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003254 case MSG_DISK_DESTROYED: {
3255 callback.onDiskDestroyed((DiskInfo) args.arg1);
3256 break;
3257 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003258 }
3259 }
3260
3261 private void notifyStorageStateChanged(String path, String oldState, String newState) {
3262 final SomeArgs args = SomeArgs.obtain();
3263 args.arg1 = path;
3264 args.arg2 = oldState;
3265 args.arg3 = newState;
3266 obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
3267 }
3268
3269 private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
3270 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003271 args.arg1 = vol.clone();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003272 args.argi2 = oldState;
3273 args.argi3 = newState;
3274 obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
3275 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003276
Jeff Sharkey50a05452015-04-29 11:24:52 -07003277 private void notifyVolumeRecordChanged(VolumeRecord rec) {
3278 final SomeArgs args = SomeArgs.obtain();
3279 args.arg1 = rec.clone();
3280 obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
3281 }
3282
3283 private void notifyVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003284 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003285 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003286 obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003287 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003288
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003289 private void notifyDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003290 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003291 args.arg1 = disk.clone();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003292 args.argi2 = volumeCount;
3293 obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003294 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003295
3296 private void notifyDiskDestroyed(DiskInfo disk) {
3297 final SomeArgs args = SomeArgs.obtain();
3298 args.arg1 = disk.clone();
3299 obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
3300 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003301 }
3302
Kenny Root38cf8862010-09-26 14:18:51 -07003303 @Override
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003304 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
3305 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
3306
3307 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003308 synchronized (mLock) {
3309 pw.println("Disks:");
3310 pw.increaseIndent();
3311 for (int i = 0; i < mDisks.size(); i++) {
3312 final DiskInfo disk = mDisks.valueAt(i);
3313 disk.dump(pw);
3314 }
3315 pw.decreaseIndent();
3316
3317 pw.println();
3318 pw.println("Volumes:");
3319 pw.increaseIndent();
3320 for (int i = 0; i < mVolumes.size(); i++) {
3321 final VolumeInfo vol = mVolumes.valueAt(i);
3322 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue;
3323 vol.dump(pw);
3324 }
3325 pw.decreaseIndent();
3326
3327 pw.println();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003328 pw.println("Records:");
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003329 pw.increaseIndent();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003330 for (int i = 0; i < mRecords.size(); i++) {
3331 final VolumeRecord note = mRecords.valueAt(i);
3332 note.dump(pw);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003333 }
3334 pw.decreaseIndent();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07003335
3336 pw.println();
3337 pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07003338 pw.println("Force adoptable: " + mForceAdoptable);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003339 }
Kenny Root38cf8862010-09-26 14:18:51 -07003340
Kenny Root38cf8862010-09-26 14:18:51 -07003341 synchronized (mObbMounts) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003342 pw.println();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003343 pw.println("mObbMounts:");
3344 pw.increaseIndent();
3345 final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet()
3346 .iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003347 while (binders.hasNext()) {
3348 Entry<IBinder, List<ObbState>> e = binders.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003349 pw.println(e.getKey() + ":");
3350 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003351 final List<ObbState> obbStates = e.getValue();
Kenny Root38cf8862010-09-26 14:18:51 -07003352 for (final ObbState obbState : obbStates) {
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003353 pw.println(obbState);
Kenny Root38cf8862010-09-26 14:18:51 -07003354 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003355 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003356 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003357 pw.decreaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003358
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003359 pw.println();
3360 pw.println("mObbPathToStateMap:");
3361 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003362 final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
3363 while (maps.hasNext()) {
3364 final Entry<String, ObbState> e = maps.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003365 pw.print(e.getKey());
3366 pw.print(" -> ");
3367 pw.println(e.getValue());
Kenny Rootaf9d6672010-10-08 09:21:39 -07003368 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003369 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003370 }
Kenny Root4161f9b2011-07-13 09:48:33 -07003371
Robert Greenwalt470fd722012-01-18 12:51:15 -08003372 pw.println();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003373 pw.println("mConnection:");
3374 pw.increaseIndent();
Robert Greenwalt470fd722012-01-18 12:51:15 -08003375 mConnector.dump(fd, pw, args);
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003376 pw.decreaseIndent();
Christopher Tate7265abe2014-11-21 13:54:45 -08003377
Christopher Tate7265abe2014-11-21 13:54:45 -08003378 pw.println();
3379 pw.print("Last maintenance: ");
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07003380 pw.println(TimeUtils.formatForLogging(mLastMaintenance));
Kenny Root38cf8862010-09-26 14:18:51 -07003381 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003382
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003383 /** {@inheritDoc} */
Jeff Sharkey48877892015-03-18 11:27:19 -07003384 @Override
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003385 public void monitor() {
3386 if (mConnector != null) {
3387 mConnector.monitor();
3388 }
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07003389 if (mCryptConnector != null) {
3390 mCryptConnector.monitor();
3391 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003392 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003393
3394 private final class MountServiceInternalImpl extends MountServiceInternal {
3395 // Not guarded by a lock.
3396 private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
3397 new CopyOnWriteArrayList<>();
3398
3399 @Override
3400 public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
3401 // No locking - CopyOnWriteArrayList
3402 mPolicies.add(policy);
3403 }
3404
3405 @Override
3406 public void onExternalStoragePolicyChanged(int uid, String packageName) {
3407 final int mountMode = getExternalStorageMountMode(uid, packageName);
3408 remountUidExternalStorage(uid, mountMode);
3409 }
3410
3411 @Override
3412 public int getExternalStorageMountMode(int uid, String packageName) {
3413 // No locking - CopyOnWriteArrayList
3414 int mountMode = Integer.MAX_VALUE;
3415 for (ExternalStorageMountPolicy policy : mPolicies) {
3416 final int policyMode = policy.getMountMode(uid, packageName);
3417 if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
3418 return Zygote.MOUNT_EXTERNAL_NONE;
3419 }
3420 mountMode = Math.min(mountMode, policyMode);
3421 }
3422 if (mountMode == Integer.MAX_VALUE) {
3423 return Zygote.MOUNT_EXTERNAL_NONE;
3424 }
3425 return mountMode;
3426 }
3427
3428 public boolean hasExternalStorage(int uid, String packageName) {
3429 // No locking - CopyOnWriteArrayList
3430 for (ExternalStorageMountPolicy policy : mPolicies) {
3431 final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
3432 if (!policyHasStorage) {
3433 return false;
3434 }
3435 }
3436 return true;
3437 }
3438 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003439}