blob: fbb31a51a01babc5463883cb1a70ad4b677c3c2c [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;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -070032import android.app.ActivityManager;
Elliott Hughesf839b4f2014-09-26 12:30:47 -070033import android.app.ActivityManagerNative;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -070034import android.app.AppOpsManager;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070035import android.app.IActivityManager;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070036import android.content.BroadcastReceiver;
Kenny Roota02b8b02010-08-05 16:14:17 -070037import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.content.Context;
39import android.content.Intent;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070040import android.content.IntentFilter;
Kenny Roota02b8b02010-08-05 16:14:17 -070041import android.content.ServiceConnection;
Jeff Sharkey275e3e42015-04-24 16:10:32 -070042import android.content.pm.IPackageMoveObserver;
43import android.content.pm.PackageManager;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070044import android.content.pm.ProviderInfo;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070045import android.content.pm.UserInfo;
Elliott Hughesf839b4f2014-09-26 12:30:47 -070046import android.content.res.Configuration;
Kenny Root02c87302010-07-01 08:10:18 -070047import android.content.res.ObbInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.net.Uri;
Kenny Root02c87302010-07-01 08:10:18 -070049import android.os.Binder;
Jeff Sharkey4c099d02015-05-15 13:45:00 -070050import android.os.DropBoxManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070051import android.os.Environment;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070052import android.os.Environment.UserEnvironment;
Jeff Sharkey48877892015-03-18 11:27:19 -070053import android.os.FileUtils;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080054import android.os.Handler;
Dianne Hackbornefa92b22013-05-03 14:11:43 -070055import android.os.HandlerThread;
Kenny Roota02b8b02010-08-05 16:14:17 -070056import android.os.IBinder;
Daniel Sandler5f27ef42010-03-16 15:42:02 -040057import android.os.Looper;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080058import android.os.Message;
Daichi Hirono9e8d9e22015-11-13 14:37:00 +090059import android.os.ParcelFileDescriptor;
Jeff Sharkeyce14cd02015-12-07 15:35:42 -070060import android.os.PowerManager;
Jeff Sharkey9527b222015-06-24 15:24:48 -070061import android.os.Process;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070062import android.os.RemoteCallbackList;
San Mehat4270e1e2010-01-29 05:32:19 -080063import android.os.RemoteException;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -080064import android.os.ServiceManager;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -070065import android.os.SystemClock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070067import android.os.UserHandle;
Emily Bernier92aa5a22014-07-07 10:11:48 -040068import android.os.UserManager;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070069import android.os.storage.DiskInfo;
Kenny Roota02b8b02010-08-05 16:14:17 -070070import android.os.storage.IMountService;
71import android.os.storage.IMountServiceListener;
72import android.os.storage.IMountShutdownObserver;
73import android.os.storage.IObbActionListener;
Svet Ganov6ee871e2015-07-10 14:29:33 -070074import android.os.storage.MountServiceInternal;
Kenny Rootaf9d6672010-10-08 09:21:39 -070075import android.os.storage.OnObbStateChangeListener;
Paul Lawrence46791e72014-04-03 09:10:26 -070076import android.os.storage.StorageManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070077import android.os.storage.StorageResultCode;
Mike Lockwood2f6a3882011-05-09 19:08:06 -070078import android.os.storage.StorageVolume;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070079import android.os.storage.VolumeInfo;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070080import android.os.storage.VolumeRecord;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070081import android.provider.MediaStore;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070082import android.provider.Settings;
Jason parksf7b3cd42011-01-27 09:28:25 -060083import android.text.TextUtils;
Jeff Sharkey1783f142015-04-17 10:52:51 -070084import android.text.format.DateUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -070085import android.util.ArrayMap;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070086import android.util.AtomicFile;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070087import android.util.Log;
San Mehata5078592010-03-25 09:36:54 -070088import android.util.Slog;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070089import android.util.TimeUtils;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070090import android.util.Xml;
Jeff Sharkey48877892015-03-18 11:27:19 -070091
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070092import libcore.io.IoUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -070093import libcore.util.EmptyArray;
Mike Lockwood2f6a3882011-05-09 19:08:06 -070094
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -080095import com.android.internal.annotations.GuardedBy;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070096import com.android.internal.app.IMediaContainerService;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070097import com.android.internal.os.SomeArgs;
Jeff Sharkey9527b222015-06-24 15:24:48 -070098import com.android.internal.os.Zygote;
Jeff Sharkey48877892015-03-18 11:27:19 -070099import com.android.internal.util.ArrayUtils;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700100import com.android.internal.util.FastXmlSerializer;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800101import com.android.internal.util.HexDump;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -0700102import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700103import com.android.internal.util.Preconditions;
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700104import com.android.internal.widget.LockPatternUtils;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700105import com.android.server.NativeDaemonConnector.Command;
Jeff Sharkey56cd6462013-06-07 15:09:15 -0700106import com.android.server.NativeDaemonConnector.SensitiveArg;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700107import com.android.server.pm.PackageManagerService;
Kenny Roota02b8b02010-08-05 16:14:17 -0700108
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700109import org.xmlpull.v1.XmlPullParser;
110import org.xmlpull.v1.XmlPullParserException;
111import org.xmlpull.v1.XmlSerializer;
112
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700113import java.io.File;
Kenny Root38cf8862010-09-26 14:18:51 -0700114import java.io.FileDescriptor;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700115import java.io.FileInputStream;
116import java.io.FileNotFoundException;
Christopher Tate7265abe2014-11-21 13:54:45 -0800117import java.io.FileOutputStream;
Kenny Root05105f72010-09-22 17:29:43 -0700118import java.io.IOException;
Kenny Root38cf8862010-09-26 14:18:51 -0700119import java.io.PrintWriter;
Kenny Root3b1abba2010-10-13 15:00:07 -0700120import java.math.BigInteger;
Paul Lawrence8e397362014-01-27 15:22:30 -0800121import java.nio.charset.StandardCharsets;
Kenny Root735de3b2010-09-30 14:11:39 -0700122import java.security.NoSuchAlgorithmException;
Kenny Root3b1abba2010-10-13 15:00:07 -0700123import java.security.spec.InvalidKeySpecException;
124import java.security.spec.KeySpec;
San Mehat22dd86e2010-01-12 12:21:18 -0800125import java.util.ArrayList;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800126import java.util.Arrays;
Kenny Roota02b8b02010-08-05 16:14:17 -0700127import java.util.HashMap;
San Mehat6cdd9c02010-02-09 14:45:20 -0800128import java.util.HashSet;
Kenny Root38cf8862010-09-26 14:18:51 -0700129import java.util.Iterator;
Kenny Roota02b8b02010-08-05 16:14:17 -0700130import java.util.LinkedList;
131import java.util.List;
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700132import java.util.Locale;
Kenny Roota02b8b02010-08-05 16:14:17 -0700133import java.util.Map;
Kenny Root38cf8862010-09-26 14:18:51 -0700134import java.util.Map.Entry;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700135import java.util.Objects;
Svet Ganov6ee871e2015-07-10 14:29:33 -0700136import java.util.concurrent.CopyOnWriteArrayList;
Kenny Root51a573c2012-05-17 13:30:28 -0700137import java.util.concurrent.CountDownLatch;
138import java.util.concurrent.TimeUnit;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700139import java.util.concurrent.TimeoutException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140
Kenny Root3b1abba2010-10-13 15:00:07 -0700141import javax.crypto.SecretKey;
142import javax.crypto.SecretKeyFactory;
143import javax.crypto.spec.PBEKeySpec;
144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145/**
Jeff Sharkey48877892015-03-18 11:27:19 -0700146 * Service responsible for various storage media. Connects to {@code vold} to
147 * watch for and manage dynamically added storage, such as SD cards and USB mass
148 * storage. Also decides how storage should be presented to users on the device.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 */
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700150class MountService extends IMountService.Stub
151 implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
Jason parks5af0b912010-11-29 09:05:25 -0600152
Christopher Tated417d622013-08-19 16:14:25 -0700153 // Static direct instance pointer for the tightly-coupled idle service to use
154 static MountService sSelf = null;
155
Jeff Sharkey56e62932015-03-21 20:41:00 -0700156 public static class Lifecycle extends SystemService {
157 private MountService mMountService;
158
159 public Lifecycle(Context context) {
160 super(context);
161 }
162
163 @Override
164 public void onStart() {
165 mMountService = new MountService(getContext());
166 publishBinderService("mount", mMountService);
167 }
168
169 @Override
170 public void onBootPhase(int phase) {
171 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
172 mMountService.systemReady();
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900173 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
174 mMountService.bootCompleted();
Jeff Sharkey56e62932015-03-21 20:41:00 -0700175 }
176 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700177
178 @Override
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700179 public void onUnlockUser(int userHandle) {
180 mMountService.onUnlockUser(userHandle);
Jeff Sharkey48877892015-03-18 11:27:19 -0700181 }
182
183 @Override
184 public void onCleanupUser(int userHandle) {
185 mMountService.onCleanupUser(userHandle);
186 }
Jeff Sharkey56e62932015-03-21 20:41:00 -0700187 }
188
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800189 private static final boolean DEBUG_EVENTS = false;
Kenny Rootb7db2722011-01-25 16:39:35 -0800190 private static final boolean DEBUG_OBB = false;
Kenny Root02c87302010-07-01 08:10:18 -0700191
Kenny Root07714d42011-08-17 17:49:28 -0700192 // Disable this since it messes up long-running cryptfs operations.
193 private static final boolean WATCHDOG_ENABLE = false;
194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 private static final String TAG = "MountService";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700196
Jeff Sharkey9756d752015-05-14 21:07:42 -0700197 private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700198 private static final String TAG_STORAGE_TRIM = "storage_trim";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199
Kenny Root305bcbf2010-09-03 07:56:38 -0700200 private static final String VOLD_TAG = "VoldConnector";
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700201 private static final String CRYPTD_TAG = "CryptdConnector";
Kenny Root305bcbf2010-09-03 07:56:38 -0700202
Kenny Rootcf0b38c2011-03-22 14:17:59 -0700203 /** Maximum number of ASEC containers allowed to be mounted. */
204 private static final int MAX_CONTAINERS = 250;
205
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700206 /** Magic value sent by MoveTask.cpp */
207 private static final int MOVE_STATUS_COPY_FINISHED = 82;
208
San Mehat4270e1e2010-01-29 05:32:19 -0800209 /*
210 * Internal vold response code constants
211 */
San Mehat22dd86e2010-01-12 12:21:18 -0800212 class VoldResponseCode {
San Mehat4270e1e2010-01-29 05:32:19 -0800213 /*
214 * 100 series - Requestion action was initiated; expect another reply
215 * before proceeding with a new command.
216 */
San Mehat22dd86e2010-01-12 12:21:18 -0800217 public static final int VolumeListResult = 110;
218 public static final int AsecListResult = 111;
San Mehatc1b4ce92010-02-16 17:13:03 -0800219 public static final int StorageUsersListResult = 112;
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700220 public static final int CryptfsGetfieldResult = 113;
San Mehat22dd86e2010-01-12 12:21:18 -0800221
San Mehat4270e1e2010-01-29 05:32:19 -0800222 /*
223 * 200 series - Requestion action has been successfully completed.
224 */
225 public static final int ShareStatusResult = 210;
San Mehat22dd86e2010-01-12 12:21:18 -0800226 public static final int AsecPathResult = 211;
San Mehat4270e1e2010-01-29 05:32:19 -0800227 public static final int ShareEnabledResult = 212;
San Mehat22dd86e2010-01-12 12:21:18 -0800228
San Mehat4270e1e2010-01-29 05:32:19 -0800229 /*
230 * 400 series - Command was accepted, but the requested action
231 * did not take place.
232 */
233 public static final int OpFailedNoMedia = 401;
234 public static final int OpFailedMediaBlank = 402;
235 public static final int OpFailedMediaCorrupt = 403;
236 public static final int OpFailedVolNotMounted = 404;
San Mehatd9709982010-02-18 11:43:03 -0800237 public static final int OpFailedStorageBusy = 405;
San Mehat2d66cef2010-03-23 11:12:52 -0700238 public static final int OpFailedStorageNotFound = 406;
San Mehat4270e1e2010-01-29 05:32:19 -0800239
240 /*
241 * 600 series - Unsolicited broadcasts.
242 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700243 public static final int DISK_CREATED = 640;
244 public static final int DISK_SIZE_CHANGED = 641;
245 public static final int DISK_LABEL_CHANGED = 642;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700246 public static final int DISK_SCANNED = 643;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700247 public static final int DISK_SYS_PATH_CHANGED = 644;
Jeff Sharkey48877892015-03-18 11:27:19 -0700248 public static final int DISK_DESTROYED = 649;
249
250 public static final int VOLUME_CREATED = 650;
251 public static final int VOLUME_STATE_CHANGED = 651;
252 public static final int VOLUME_FS_TYPE_CHANGED = 652;
253 public static final int VOLUME_FS_UUID_CHANGED = 653;
254 public static final int VOLUME_FS_LABEL_CHANGED = 654;
255 public static final int VOLUME_PATH_CHANGED = 655;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700256 public static final int VOLUME_INTERNAL_PATH_CHANGED = 656;
Jeff Sharkey48877892015-03-18 11:27:19 -0700257 public static final int VOLUME_DESTROYED = 659;
Svetoslavf23b64d2013-04-25 14:45:54 -0700258
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700259 public static final int MOVE_STATUS = 660;
Jeff Sharkey9756d752015-05-14 21:07:42 -0700260 public static final int BENCHMARK_RESULT = 661;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700261 public static final int TRIM_RESULT = 662;
San Mehat22dd86e2010-01-12 12:21:18 -0800262 }
263
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700264 private static final int VERSION_INIT = 1;
265 private static final int VERSION_ADD_PRIMARY = 2;
Jeff Sharkeyfced5342015-05-10 14:53:34 -0700266 private static final int VERSION_FIX_PRIMARY = 3;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700267
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700268 private static final String TAG_VOLUMES = "volumes";
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700269 private static final String ATTR_VERSION = "version";
270 private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid";
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700271 private static final String ATTR_FORCE_ADOPTABLE = "forceAdoptable";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700272 private static final String TAG_VOLUME = "volume";
273 private static final String ATTR_TYPE = "type";
274 private static final String ATTR_FS_UUID = "fsUuid";
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700275 private static final String ATTR_PART_GUID = "partGuid";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700276 private static final String ATTR_NICKNAME = "nickname";
277 private static final String ATTR_USER_FLAGS = "userFlags";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700278 private static final String ATTR_CREATED_MILLIS = "createdMillis";
279 private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis";
280 private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700281
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700282 private final AtomicFile mSettingsFile;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700283
Jeff Sharkey48877892015-03-18 11:27:19 -0700284 /**
285 * <em>Never</em> hold the lock while performing downcalls into vold, since
286 * unsolicited events can suddenly appear to update data structures.
287 */
288 private final Object mLock = new Object();
289
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700290 /** Set of users that we know are unlocked. */
Jeff Sharkey48877892015-03-18 11:27:19 -0700291 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700292 private int[] mLocalUnlockedUsers = EmptyArray.INT;
293 /** Set of users that system knows are unlocked. */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800294 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700295 private int[] mSystemUnlockedUsers = EmptyArray.INT;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700296
297 /** Map from disk ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700298 @GuardedBy("mLock")
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700299 private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700300 /** Map from volume ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700301 @GuardedBy("mLock")
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700302 private final ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
Jeff Sharkey48877892015-03-18 11:27:19 -0700303
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700304 /** Map from UUID to record */
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700305 @GuardedBy("mLock")
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700306 private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>();
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700307 @GuardedBy("mLock")
308 private String mPrimaryStorageUuid;
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700309 @GuardedBy("mLock")
310 private boolean mForceAdoptable;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700311
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700312 /** Map from disk ID to latches */
313 @GuardedBy("mLock")
314 private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
315
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700316 @GuardedBy("mLock")
317 private IPackageMoveObserver mMoveCallback;
318 @GuardedBy("mLock")
319 private String mMoveTargetUuid;
320
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700321 private VolumeInfo findVolumeByIdOrThrow(String id) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700322 synchronized (mLock) {
323 final VolumeInfo vol = mVolumes.get(id);
324 if (vol != null) {
325 return vol;
326 }
327 }
328 throw new IllegalArgumentException("No volume found for ID " + id);
329 }
330
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700331 private String findVolumeIdForPathOrThrow(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700332 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700333 for (int i = 0; i < mVolumes.size(); i++) {
334 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700335 if (vol.path != null && path.startsWith(vol.path)) {
336 return vol.id;
Jeff Sharkey48877892015-03-18 11:27:19 -0700337 }
338 }
339 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700340 throw new IllegalArgumentException("No volume found for path " + path);
Jeff Sharkey48877892015-03-18 11:27:19 -0700341 }
342
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700343 private VolumeRecord findRecordForPath(String path) {
344 synchronized (mLock) {
345 for (int i = 0; i < mVolumes.size(); i++) {
346 final VolumeInfo vol = mVolumes.valueAt(i);
347 if (vol.path != null && path.startsWith(vol.path)) {
348 return mRecords.get(vol.fsUuid);
349 }
350 }
351 }
352 return null;
353 }
354
355 private String scrubPath(String path) {
356 if (path.startsWith(Environment.getDataDirectory().getAbsolutePath())) {
357 return "internal";
358 }
359 final VolumeRecord rec = findRecordForPath(path);
360 if (rec == null || rec.createdMillis == 0) {
361 return "unknown";
362 } else {
363 return "ext:" + (int) ((System.currentTimeMillis() - rec.createdMillis)
364 / DateUtils.WEEK_IN_MILLIS) + "w";
365 }
366 }
367
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700368 private @Nullable VolumeInfo findStorageForUuid(String volumeUuid) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700369 final StorageManager storage = mContext.getSystemService(StorageManager.class);
370 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700371 return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL);
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700372 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
373 return storage.getPrimaryPhysicalVolume();
374 } else {
375 return storage.findEmulatedForPrivate(storage.findVolumeByUuid(volumeUuid));
376 }
377 }
378
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700379 private boolean shouldBenchmark() {
380 final long benchInterval = Settings.Global.getLong(mContext.getContentResolver(),
381 Settings.Global.STORAGE_BENCHMARK_INTERVAL, DateUtils.WEEK_IN_MILLIS);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700382 if (benchInterval == -1) {
383 return false;
384 } else if (benchInterval == 0) {
385 return true;
386 }
387
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700388 synchronized (mLock) {
389 for (int i = 0; i < mVolumes.size(); i++) {
390 final VolumeInfo vol = mVolumes.valueAt(i);
391 final VolumeRecord rec = mRecords.get(vol.fsUuid);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700392 if (vol.isMountedWritable() && rec != null) {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700393 final long benchAge = System.currentTimeMillis() - rec.lastBenchMillis;
394 if (benchAge >= benchInterval) {
395 return true;
396 }
397 }
398 }
399 return false;
400 }
401 }
402
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700403 private CountDownLatch findOrCreateDiskScanLatch(String diskId) {
404 synchronized (mLock) {
405 CountDownLatch latch = mDiskScanLatches.get(diskId);
406 if (latch == null) {
407 latch = new CountDownLatch(1);
408 mDiskScanLatches.put(diskId, latch);
409 }
410 return latch;
411 }
412 }
413
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800414 private static String escapeNull(String arg) {
415 if (TextUtils.isEmpty(arg)) {
416 return "!";
417 } else {
418 if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
419 throw new IllegalArgumentException(arg);
420 }
421 return arg;
422 }
423 }
424
Paul Lawrence8e397362014-01-27 15:22:30 -0800425 /** List of crypto types.
426 * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
427 * corresponding commands in CommandListener.cpp */
428 public static final String[] CRYPTO_TYPES
429 = { "password", "default", "pattern", "pin" };
430
Brian Carlstrom7395a8a2014-04-28 22:11:01 -0700431 private final Context mContext;
Brian Carlstromdfad99a2014-05-07 15:21:14 -0700432 private final NativeDaemonConnector mConnector;
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700433 private final NativeDaemonConnector mCryptConnector;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700434
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700435 private volatile boolean mSystemReady = false;
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900436 private volatile boolean mBootCompleted = false;
Jeff Sharkey48877892015-03-18 11:27:19 -0700437 private volatile boolean mDaemonConnected = false;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700438
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700439 private PackageManagerService mPms;
440
441 private final Callbacks mCallbacks;
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700442 private final LockPatternUtils mLockPatternUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -0700443
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700444 // Two connectors - mConnector & mCryptConnector
445 private final CountDownLatch mConnectedSignal = new CountDownLatch(2);
Jeff Sharkey0be607c2012-11-14 14:39:19 -0800446 private final CountDownLatch mAsecsScanned = new CountDownLatch(1);
Jeff Sharkey48877892015-03-18 11:27:19 -0700447
448 private final Object mUnmountLock = new Object();
449 @GuardedBy("mUnmountLock")
450 private CountDownLatch mUnmountSignal;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800451
San Mehat6cdd9c02010-02-09 14:45:20 -0800452 /**
453 * Private hash of currently mounted secure containers.
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800454 * Used as a lock in methods to manipulate secure containers.
San Mehat6cdd9c02010-02-09 14:45:20 -0800455 */
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800456 final private HashSet<String> mAsecMountSet = new HashSet<String>();
San Mehat6cdd9c02010-02-09 14:45:20 -0800457
Kenny Root02c87302010-07-01 08:10:18 -0700458 /**
Kenny Root3b1abba2010-10-13 15:00:07 -0700459 * The size of the crypto algorithm key in bits for OBB files. Currently
460 * Twofish is used which takes 128-bit keys.
461 */
462 private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
463
464 /**
465 * The number of times to run SHA1 in the PBKDF2 function for OBB files.
466 * 1024 is reasonably secure and not too slow.
467 */
468 private static final int PBKDF2_HASH_ROUNDS = 1024;
469
470 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700471 * Mounted OBB tracking information. Used to track the current state of all
472 * OBBs.
Kenny Root02c87302010-07-01 08:10:18 -0700473 */
Kenny Root735de3b2010-09-30 14:11:39 -0700474 final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700475
476 /** Map from raw paths to {@link ObbState}. */
Kenny Roota02b8b02010-08-05 16:14:17 -0700477 final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
478
Svet Ganov6ee871e2015-07-10 14:29:33 -0700479 // Not guarded by a lock.
480 private final MountServiceInternalImpl mMountServiceInternal = new MountServiceInternalImpl();
481
Kenny Roota02b8b02010-08-05 16:14:17 -0700482 class ObbState implements IBinder.DeathRecipient {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700483 public ObbState(String rawPath, String canonicalPath, int callingUid,
484 IObbActionListener token, int nonce) {
485 this.rawPath = rawPath;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700486 this.canonicalPath = canonicalPath;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700487
488 this.ownerGid = UserHandle.getSharedAppGid(callingUid);
Kenny Rootaf9d6672010-10-08 09:21:39 -0700489 this.token = token;
490 this.nonce = nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700491 }
492
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700493 final String rawPath;
494 final String canonicalPath;
Kenny Roota02b8b02010-08-05 16:14:17 -0700495
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700496 final int ownerGid;
Kenny Roota02b8b02010-08-05 16:14:17 -0700497
Kenny Rootaf9d6672010-10-08 09:21:39 -0700498 // Token of remote Binder caller
499 final IObbActionListener token;
500
501 // Identifier to pass back to the token
502 final int nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700503
Kenny Root735de3b2010-09-30 14:11:39 -0700504 public IBinder getBinder() {
505 return token.asBinder();
506 }
507
Kenny Roota02b8b02010-08-05 16:14:17 -0700508 @Override
509 public void binderDied() {
510 ObbAction action = new UnmountObbAction(this, true);
511 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root735de3b2010-09-30 14:11:39 -0700512 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700513
Kenny Root5919ac62010-10-05 09:49:40 -0700514 public void link() throws RemoteException {
515 getBinder().linkToDeath(this, 0);
516 }
517
518 public void unlink() {
Kenny Root735de3b2010-09-30 14:11:39 -0700519 getBinder().unlinkToDeath(this, 0);
Kenny Roota02b8b02010-08-05 16:14:17 -0700520 }
Kenny Root38cf8862010-09-26 14:18:51 -0700521
522 @Override
523 public String toString() {
524 StringBuilder sb = new StringBuilder("ObbState{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700525 sb.append("rawPath=").append(rawPath);
526 sb.append(",canonicalPath=").append(canonicalPath);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700527 sb.append(",ownerGid=").append(ownerGid);
528 sb.append(",token=").append(token);
529 sb.append(",binder=").append(getBinder());
Kenny Root38cf8862010-09-26 14:18:51 -0700530 sb.append('}');
531 return sb.toString();
532 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700533 }
534
535 // OBB Action Handler
536 final private ObbActionHandler mObbActionHandler;
537
538 // OBB action handler messages
539 private static final int OBB_RUN_ACTION = 1;
540 private static final int OBB_MCS_BOUND = 2;
541 private static final int OBB_MCS_UNBIND = 3;
542 private static final int OBB_MCS_RECONNECT = 4;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700543 private static final int OBB_FLUSH_MOUNT_STATE = 5;
Kenny Roota02b8b02010-08-05 16:14:17 -0700544
545 /*
546 * Default Container Service information
547 */
548 static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
549 "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
550
551 final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
552
553 class DefaultContainerConnection implements ServiceConnection {
Jeff Sharkey48877892015-03-18 11:27:19 -0700554 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700555 public void onServiceConnected(ComponentName name, IBinder service) {
556 if (DEBUG_OBB)
557 Slog.i(TAG, "onServiceConnected");
558 IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
559 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
560 }
561
Jeff Sharkey48877892015-03-18 11:27:19 -0700562 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700563 public void onServiceDisconnected(ComponentName name) {
564 if (DEBUG_OBB)
565 Slog.i(TAG, "onServiceDisconnected");
566 }
567 };
568
569 // Used in the ObbActionHandler
570 private IMediaContainerService mContainerService = null;
Kenny Root02c87302010-07-01 08:10:18 -0700571
Christopher Tate7265abe2014-11-21 13:54:45 -0800572 // Last fstrim operation tracking
573 private static final String LAST_FSTRIM_FILE = "last-fstrim";
574 private final File mLastMaintenanceFile;
575 private long mLastMaintenance;
576
Kenny Root02c87302010-07-01 08:10:18 -0700577 // Handler messages
Jeff Sharkey48877892015-03-18 11:27:19 -0700578 private static final int H_SYSTEM_READY = 1;
579 private static final int H_DAEMON_CONNECTED = 2;
580 private static final int H_SHUTDOWN = 3;
581 private static final int H_FSTRIM = 4;
582 private static final int H_VOLUME_MOUNT = 5;
583 private static final int H_VOLUME_BROADCAST = 6;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700584 private static final int H_INTERNAL_BROADCAST = 7;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700585 private static final int H_VOLUME_UNMOUNT = 8;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800586 private static final int H_PARTITION_FORGET = 9;
587 private static final int H_RESET = 10;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800588
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400589 class MountServiceHandler extends Handler {
Jeff Sharkey48877892015-03-18 11:27:19 -0700590 public MountServiceHandler(Looper looper) {
591 super(looper);
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400592 }
593
Jason parks5af0b912010-11-29 09:05:25 -0600594 @Override
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800595 public void handleMessage(Message msg) {
596 switch (msg.what) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700597 case H_SYSTEM_READY: {
Jeff Sharkey48877892015-03-18 11:27:19 -0700598 handleSystemReady();
599 break;
600 }
601 case H_DAEMON_CONNECTED: {
602 handleDaemonConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700603 break;
604 }
Christopher Tated417d622013-08-19 16:14:25 -0700605 case H_FSTRIM: {
Jeff Sharkey1783f142015-04-17 10:52:51 -0700606 if (!isReady()) {
607 Slog.i(TAG, "fstrim requested, but no daemon connection yet; trying again");
Christopher Tate7618db12015-04-28 16:32:55 -0700608 sendMessageDelayed(obtainMessage(H_FSTRIM, msg.obj),
609 DateUtils.SECOND_IN_MILLIS);
610 break;
Jeff Sharkey1783f142015-04-17 10:52:51 -0700611 }
612
Christopher Tated417d622013-08-19 16:14:25 -0700613 Slog.i(TAG, "Running fstrim idle maintenance");
Christopher Tate7265abe2014-11-21 13:54:45 -0800614
615 // Remember when we kicked it off
616 try {
617 mLastMaintenance = System.currentTimeMillis();
618 mLastMaintenanceFile.setLastModified(mLastMaintenance);
619 } catch (Exception e) {
620 Slog.e(TAG, "Unable to record last fstrim!");
621 }
622
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700623 final boolean shouldBenchmark = shouldBenchmark();
Christopher Tated417d622013-08-19 16:14:25 -0700624 try {
625 // This method must be run on the main (handler) thread,
626 // so it is safe to directly call into vold.
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700627 mConnector.execute("fstrim", shouldBenchmark ? "dotrimbench" : "dotrim");
Christopher Tated417d622013-08-19 16:14:25 -0700628 } catch (NativeDaemonConnectorException ndce) {
629 Slog.e(TAG, "Failed to run fstrim!");
630 }
Christopher Tate7265abe2014-11-21 13:54:45 -0800631
Christopher Tated417d622013-08-19 16:14:25 -0700632 // invoke the completion callback, if any
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700633 // TODO: fstrim is non-blocking, so remove this useless callback
Christopher Tated417d622013-08-19 16:14:25 -0700634 Runnable callback = (Runnable) msg.obj;
635 if (callback != null) {
636 callback.run();
637 }
638 break;
639 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700640 case H_SHUTDOWN: {
641 final IMountShutdownObserver obs = (IMountShutdownObserver) msg.obj;
642 boolean success = false;
643 try {
644 success = mConnector.execute("volume", "shutdown").isClassOk();
645 } catch (NativeDaemonConnectorException ignored) {
646 }
647 if (obs != null) {
648 try {
649 obs.onShutDownComplete(success ? 0 : -1);
650 } catch (RemoteException ignored) {
651 }
652 }
653 break;
654 }
655 case H_VOLUME_MOUNT: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700656 final VolumeInfo vol = (VolumeInfo) msg.obj;
Jeff Sharkey2e606d72015-07-27 14:19:54 -0700657 if (isMountDisallowed(vol)) {
658 Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");
659 break;
660 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700661 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700662 mConnector.execute("volume", "mount", vol.id, vol.mountFlags,
663 vol.mountUserId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700664 } catch (NativeDaemonConnectorException ignored) {
665 }
666 break;
667 }
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700668 case H_VOLUME_UNMOUNT: {
669 final VolumeInfo vol = (VolumeInfo) msg.obj;
670 unmount(vol.getId());
671 break;
672 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700673 case H_VOLUME_BROADCAST: {
674 final StorageVolume userVol = (StorageVolume) msg.obj;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700675 final String envState = userVol.getState();
676 Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + envState + " to "
Jeff Sharkey48877892015-03-18 11:27:19 -0700677 + userVol.getOwner());
678
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700679 final String action = VolumeInfo.getBroadcastForEnvironment(envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700680 if (action != null) {
681 final Intent intent = new Intent(action,
682 Uri.fromFile(userVol.getPathFile()));
683 intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, userVol);
684 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
685 mContext.sendBroadcastAsUser(intent, userVol.getOwner());
686 }
687 break;
688 }
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700689 case H_INTERNAL_BROADCAST: {
690 // Internal broadcasts aimed at system components, not for
691 // third-party apps.
692 final Intent intent = (Intent) msg.obj;
693 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
694 android.Manifest.permission.WRITE_MEDIA_STORAGE);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800695 break;
696 }
697 case H_PARTITION_FORGET: {
698 final String partGuid = (String) msg.obj;
699 forgetPartition(partGuid);
700 break;
701 }
702 case H_RESET: {
703 resetIfReadyAndConnected();
704 break;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700705 }
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800706 }
707 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700708 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700709
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700710 private final Handler mHandler;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800711
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700712 private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
713 @Override
714 public void onReceive(Context context, Intent intent) {
715 final String action = intent.getAction();
716 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700717 Preconditions.checkArgument(userId >= 0);
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700718
719 try {
720 if (Intent.ACTION_USER_ADDED.equals(action)) {
721 final UserManager um = mContext.getSystemService(UserManager.class);
722 final int userSerialNumber = um.getUserSerialNumber(userId);
723 mConnector.execute("volume", "user_added", userId, userSerialNumber);
724 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700725 synchronized (mVolumes) {
726 final int size = mVolumes.size();
727 for (int i = 0; i < size; i++) {
728 final VolumeInfo vol = mVolumes.valueAt(i);
729 if (vol.mountUserId == userId) {
730 vol.mountUserId = UserHandle.USER_NULL;
731 mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
732 }
733 }
734 }
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700735 mConnector.execute("volume", "user_removed", userId);
736 }
737 } catch (NativeDaemonConnectorException e) {
738 Slog.w(TAG, "Failed to send user details to vold", e);
739 }
740 }
741 };
742
Jeff Sharkey56e62932015-03-21 20:41:00 -0700743 @Override
744 public void waitForAsecScan() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700745 waitForLatch(mAsecsScanned, "mAsecsScanned");
Kenny Root51a573c2012-05-17 13:30:28 -0700746 }
747
San Mehat207e5382010-02-04 20:46:54 -0800748 private void waitForReady() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700749 waitForLatch(mConnectedSignal, "mConnectedSignal");
Kenny Root51a573c2012-05-17 13:30:28 -0700750 }
751
Jeff Sharkey48877892015-03-18 11:27:19 -0700752 private void waitForLatch(CountDownLatch latch, String condition) {
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700753 try {
754 waitForLatch(latch, condition, -1);
755 } catch (TimeoutException ignored) {
756 }
757 }
758
759 private void waitForLatch(CountDownLatch latch, String condition, long timeoutMillis)
760 throws TimeoutException {
761 final long startMillis = SystemClock.elapsedRealtime();
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700762 while (true) {
Kenny Root51a573c2012-05-17 13:30:28 -0700763 try {
764 if (latch.await(5000, TimeUnit.MILLISECONDS)) {
San Mehat207e5382010-02-04 20:46:54 -0800765 return;
Kenny Root51a573c2012-05-17 13:30:28 -0700766 } else {
767 Slog.w(TAG, "Thread " + Thread.currentThread().getName()
Jeff Sharkey48877892015-03-18 11:27:19 -0700768 + " still waiting for " + condition + "...");
San Mehat207e5382010-02-04 20:46:54 -0800769 }
Kenny Root51a573c2012-05-17 13:30:28 -0700770 } catch (InterruptedException e) {
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700771 Slog.w(TAG, "Interrupt while waiting for " + condition);
San Mehat207e5382010-02-04 20:46:54 -0800772 }
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700773 if (timeoutMillis > 0 && SystemClock.elapsedRealtime() > startMillis + timeoutMillis) {
774 throw new TimeoutException("Thread " + Thread.currentThread().getName()
775 + " gave up waiting for " + condition + " after " + timeoutMillis + "ms");
776 }
San Mehat207e5382010-02-04 20:46:54 -0800777 }
San Mehat1f6301e2010-01-07 22:40:27 -0800778 }
Kenny Root02c87302010-07-01 08:10:18 -0700779
Paul Lawrence945490c2014-03-27 16:37:28 +0000780 private boolean isReady() {
781 try {
782 return mConnectedSignal.await(0, TimeUnit.MILLISECONDS);
783 } catch (InterruptedException e) {
784 return false;
785 }
786 }
787
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700788 private void handleSystemReady() {
Jeff Sharkey8924e872015-11-30 12:52:10 -0700789 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800790 resetIfReadyAndConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700791
Jeff Sharkey48877892015-03-18 11:27:19 -0700792 // Start scheduling nominally-daily fstrim operations
Christopher Tate115afda2014-06-06 19:06:26 -0700793 MountServiceIdler.scheduleIdlePass(mContext);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700794 }
795
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700796 /**
797 * MediaProvider has a ton of code that makes assumptions about storage
798 * paths never changing, so we outright kill them to pick up new state.
799 */
800 @Deprecated
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700801 private void killMediaProvider(List<UserInfo> users) {
802 if (users == null) return;
803
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700804 final long token = Binder.clearCallingIdentity();
805 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700806 for (UserInfo user : users) {
807 // System user does not have media provider, so skip.
808 if (user.isSystemOnly()) continue;
809
810 final ProviderInfo provider =
811 mPms.resolveContentProvider(MediaStore.AUTHORITY, 0, user.id);
812 if (provider != null) {
813 final IActivityManager am = ActivityManagerNative.getDefault();
814 try {
815 am.killApplicationWithAppId(provider.applicationInfo.packageName,
816 UserHandle.getAppId(provider.applicationInfo.uid), "vold reset");
817 // We only need to run this once. It will kill all users' media processes.
818 break;
819 } catch (RemoteException e) {
820 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700821 }
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700822 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700823 } finally {
824 Binder.restoreCallingIdentity(token);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700825 }
826 }
827
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800828 private void addInternalVolumeLocked() {
Amith Yamasania7892482015-08-07 11:09:05 -0700829 // Create a stub volume that represents internal storage
830 final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
831 VolumeInfo.TYPE_PRIVATE, null, null);
832 internal.state = VolumeInfo.STATE_MOUNTED;
833 internal.path = Environment.getDataDirectory().getAbsolutePath();
834 mVolumes.put(internal.id, internal);
835 }
836
Jeff Sharkey8924e872015-11-30 12:52:10 -0700837 private void initIfReadyAndConnected() {
838 Slog.d(TAG, "Thinking about init, mSystemReady=" + mSystemReady
839 + ", mDaemonConnected=" + mDaemonConnected);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700840 if (mSystemReady && mDaemonConnected
841 && !StorageManager.isNativeFileBasedEncryptionEnabled()) {
842 // When booting a device without native support, make sure that our
843 // user directories are locked or unlocked based on the current
844 // emulation status.
845 final boolean initLocked = StorageManager.isEmulatedFileBasedEncryptionEnabled();
846 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Jeff Sharkey8924e872015-11-30 12:52:10 -0700847 for (UserInfo user : users) {
848 try {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700849 if (initLocked) {
850 mCryptConnector.execute("cryptfs", "lock_user_key", user.id);
851 } else {
852 mCryptConnector.execute("cryptfs", "unlock_user_key", user.id,
853 user.serialNumber, "!");
854 }
Jeff Sharkey8924e872015-11-30 12:52:10 -0700855 } catch (NativeDaemonConnectorException e) {
856 Slog.w(TAG, "Failed to init vold", e);
857 }
858 }
859 }
860 }
861
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800862 private void resetIfReadyAndConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700863 Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
864 + ", mDaemonConnected=" + mDaemonConnected);
865 if (mSystemReady && mDaemonConnected) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800866 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700867 killMediaProvider(users);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700868
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700869 final int[] systemUnlockedUsers;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800870 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700871 systemUnlockedUsers = mSystemUnlockedUsers;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700872
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800873 mDisks.clear();
874 mVolumes.clear();
875
876 addInternalVolumeLocked();
877 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700878
Jeff Sharkey48877892015-03-18 11:27:19 -0700879 try {
880 mConnector.execute("volume", "reset");
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700881
882 // Tell vold about all existing and started users
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700883 for (UserInfo user : users) {
884 mConnector.execute("volume", "user_added", user.id, user.serialNumber);
885 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700886 for (int userId : systemUnlockedUsers) {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700887 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey50a05452015-04-29 11:24:52 -0700888 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700889 } catch (NativeDaemonConnectorException e) {
890 Slog.w(TAG, "Failed to reset vold", e);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700891 }
892 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700893 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700894
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700895 private void onUnlockUser(int userId) {
896 Slog.d(TAG, "onUnlockUser " + userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700897
898 // We purposefully block here to make sure that user-specific
899 // staging area is ready so it's ready for zygote-forked apps to
900 // bind mount against.
901 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700902 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700903 } catch (NativeDaemonConnectorException ignored) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700904 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700905
906 // Record user as started so newly mounted volumes kick off events
907 // correctly, then synthesize events for any already-mounted volumes.
908 synchronized (mVolumes) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700909 for (int i = 0; i < mVolumes.size(); i++) {
910 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey46349872015-07-28 10:49:47 -0700911 if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700912 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey48877892015-03-18 11:27:19 -0700913 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700914
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700915 final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
916 mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700917 }
918 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700919 mSystemUnlockedUsers = ArrayUtils.appendInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700920 }
921 }
922
923 private void onCleanupUser(int userId) {
924 Slog.d(TAG, "onCleanupUser " + userId);
925
926 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700927 mConnector.execute("volume", "user_stopped", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700928 } catch (NativeDaemonConnectorException ignored) {
929 }
930
931 synchronized (mVolumes) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700932 mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700933 }
934 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700935
Christopher Tated417d622013-08-19 16:14:25 -0700936 void runIdleMaintenance(Runnable callback) {
937 mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
938 }
939
Christopher Tate7265abe2014-11-21 13:54:45 -0800940 // Binder entry point for kicking off an immediate fstrim
941 @Override
942 public void runMaintenance() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700943 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Christopher Tate7265abe2014-11-21 13:54:45 -0800944 runIdleMaintenance(null);
945 }
946
947 @Override
948 public long lastMaintenance() {
949 return mLastMaintenance;
950 }
951
San Mehat4270e1e2010-01-29 05:32:19 -0800952 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800953 * Callback from NativeDaemonConnector
954 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700955 @Override
San Mehat4270e1e2010-01-29 05:32:19 -0800956 public void onDaemonConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700957 mDaemonConnected = true;
958 mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();
959 }
960
961 private void handleDaemonConnected() {
Jeff Sharkey8924e872015-11-30 12:52:10 -0700962 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800963 resetIfReadyAndConnected();
Jeff Sharkey48877892015-03-18 11:27:19 -0700964
San Mehat4270e1e2010-01-29 05:32:19 -0800965 /*
Jeff Sharkey48877892015-03-18 11:27:19 -0700966 * Now that we've done our initialization, release
967 * the hounds!
San Mehat4270e1e2010-01-29 05:32:19 -0800968 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700969 mConnectedSignal.countDown();
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700970 if (mConnectedSignal.getCount() != 0) {
971 // More daemons need to connect
972 return;
973 }
Mike Lockwood7fa24aa2011-03-23 14:52:34 -0400974
Jeff Sharkey48877892015-03-18 11:27:19 -0700975 // On an encrypted device we can't see system properties yet, so pull
976 // the system locale out of the mount service.
977 if ("".equals(SystemProperties.get("vold.encrypt_progress"))) {
978 copyLocaleFromMountService();
979 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700980
Jeff Sharkey48877892015-03-18 11:27:19 -0700981 // Let package manager load internal ASECs.
982 mPms.scanAvailableAsecs();
Mike Lockwood7fa24aa2011-03-23 14:52:34 -0400983
Jeff Sharkey48877892015-03-18 11:27:19 -0700984 // Notify people waiting for ASECs to be scanned that it's done.
985 mAsecsScanned.countDown();
San Mehat4270e1e2010-01-29 05:32:19 -0800986 }
987
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700988 private void copyLocaleFromMountService() {
989 String systemLocale;
990 try {
991 systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
992 } catch (RemoteException e) {
993 return;
994 }
995 if (TextUtils.isEmpty(systemLocale)) {
996 return;
997 }
998
999 Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
1000 Locale locale = Locale.forLanguageTag(systemLocale);
1001 Configuration config = new Configuration();
1002 config.setLocale(locale);
1003 try {
1004 ActivityManagerNative.getDefault().updateConfiguration(config);
1005 } catch (RemoteException e) {
1006 Slog.e(TAG, "Error setting system locale from mount service", e);
1007 }
Elliott Hughes9c33f282014-10-13 12:39:56 -07001008
1009 // Temporary workaround for http://b/17945169.
1010 Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
Narayan Kamathd30dbb82015-01-15 14:48:15 +00001011 SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001012 }
1013
San Mehat4270e1e2010-01-29 05:32:19 -08001014 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001015 * Callback from NativeDaemonConnector
1016 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001017 @Override
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001018 public boolean onCheckHoldWakeLock(int code) {
1019 return false;
1020 }
1021
1022 /**
1023 * Callback from NativeDaemonConnector
1024 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001025 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001026 public boolean onEvent(int code, String raw, String[] cooked) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001027 synchronized (mLock) {
1028 return onEventLocked(code, raw, cooked);
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -08001029 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001030 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001031
Jeff Sharkey48877892015-03-18 11:27:19 -07001032 private boolean onEventLocked(int code, String raw, String[] cooked) {
1033 switch (code) {
1034 case VoldResponseCode.DISK_CREATED: {
1035 if (cooked.length != 3) break;
1036 final String id = cooked[1];
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001037 int flags = Integer.parseInt(cooked[2]);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001038 if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false)
1039 || mForceAdoptable) {
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001040 flags |= DiskInfo.FLAG_ADOPTABLE;
1041 }
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001042 mDisks.put(id, new DiskInfo(id, flags));
Jeff Sharkey48877892015-03-18 11:27:19 -07001043 break;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001044 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001045 case VoldResponseCode.DISK_SIZE_CHANGED: {
1046 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001047 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001048 if (disk != null) {
1049 disk.size = Long.parseLong(cooked[2]);
San Mehat4270e1e2010-01-29 05:32:19 -08001050 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001051 break;
1052 }
1053 case VoldResponseCode.DISK_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001054 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001055 if (disk != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001056 final StringBuilder builder = new StringBuilder();
1057 for (int i = 2; i < cooked.length; i++) {
1058 builder.append(cooked[i]).append(' ');
1059 }
1060 disk.label = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001061 }
1062 break;
1063 }
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001064 case VoldResponseCode.DISK_SCANNED: {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001065 if (cooked.length != 2) break;
1066 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001067 if (disk != null) {
1068 onDiskScannedLocked(disk);
1069 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -07001070 break;
1071 }
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001072 case VoldResponseCode.DISK_SYS_PATH_CHANGED: {
1073 if (cooked.length != 3) break;
1074 final DiskInfo disk = mDisks.get(cooked[1]);
1075 if (disk != null) {
1076 disk.sysPath = cooked[2];
1077 }
1078 break;
1079 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001080 case VoldResponseCode.DISK_DESTROYED: {
1081 if (cooked.length != 2) break;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07001082 final DiskInfo disk = mDisks.remove(cooked[1]);
1083 if (disk != null) {
1084 mCallbacks.notifyDiskDestroyed(disk);
1085 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001086 break;
1087 }
San Mehat4270e1e2010-01-29 05:32:19 -08001088
Jeff Sharkey48877892015-03-18 11:27:19 -07001089 case VoldResponseCode.VOLUME_CREATED: {
Jeff Sharkey48877892015-03-18 11:27:19 -07001090 final String id = cooked[1];
1091 final int type = Integer.parseInt(cooked[2]);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001092 final String diskId = TextUtils.nullIfEmpty(cooked[3]);
1093 final String partGuid = TextUtils.nullIfEmpty(cooked[4]);
1094
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001095 final DiskInfo disk = mDisks.get(diskId);
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07001096 final VolumeInfo vol = new VolumeInfo(id, type, disk, partGuid);
Jeff Sharkey48877892015-03-18 11:27:19 -07001097 mVolumes.put(id, vol);
1098 onVolumeCreatedLocked(vol);
1099 break;
1100 }
1101 case VoldResponseCode.VOLUME_STATE_CHANGED: {
1102 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001103 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001104 if (vol != null) {
1105 final int oldState = vol.state;
1106 final int newState = Integer.parseInt(cooked[2]);
1107 vol.state = newState;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001108 onVolumeStateChangedLocked(vol, oldState, newState);
Jeff Sharkey48877892015-03-18 11:27:19 -07001109 }
1110 break;
1111 }
1112 case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: {
1113 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001114 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001115 if (vol != null) {
1116 vol.fsType = cooked[2];
1117 }
1118 break;
1119 }
1120 case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
1121 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001122 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001123 if (vol != null) {
1124 vol.fsUuid = cooked[2];
1125 }
1126 break;
1127 }
1128 case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001129 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001130 if (vol != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001131 final StringBuilder builder = new StringBuilder();
1132 for (int i = 2; i < cooked.length; i++) {
1133 builder.append(cooked[i]).append(' ');
1134 }
1135 vol.fsLabel = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001136 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001137 // TODO: notify listeners that label changed
Jeff Sharkey48877892015-03-18 11:27:19 -07001138 break;
1139 }
1140 case VoldResponseCode.VOLUME_PATH_CHANGED: {
1141 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001142 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001143 if (vol != null) {
1144 vol.path = cooked[2];
1145 }
1146 break;
1147 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001148 case VoldResponseCode.VOLUME_INTERNAL_PATH_CHANGED: {
1149 if (cooked.length != 3) break;
1150 final VolumeInfo vol = mVolumes.get(cooked[1]);
1151 if (vol != null) {
1152 vol.internalPath = cooked[2];
1153 }
1154 break;
1155 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001156 case VoldResponseCode.VOLUME_DESTROYED: {
1157 if (cooked.length != 2) break;
1158 mVolumes.remove(cooked[1]);
1159 break;
1160 }
San Mehat4270e1e2010-01-29 05:32:19 -08001161
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001162 case VoldResponseCode.MOVE_STATUS: {
1163 final int status = Integer.parseInt(cooked[1]);
1164 onMoveStatusLocked(status);
1165 break;
1166 }
Jeff Sharkey9756d752015-05-14 21:07:42 -07001167 case VoldResponseCode.BENCHMARK_RESULT: {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001168 if (cooked.length != 7) break;
1169 final String path = cooked[1];
1170 final String ident = cooked[2];
1171 final long create = Long.parseLong(cooked[3]);
1172 final long drop = Long.parseLong(cooked[4]);
1173 final long run = Long.parseLong(cooked[5]);
1174 final long destroy = Long.parseLong(cooked[6]);
1175
Jeff Sharkey9756d752015-05-14 21:07:42 -07001176 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001177 dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
1178 + " " + ident + " " + create + " " + run + " " + destroy);
1179
1180 final VolumeRecord rec = findRecordForPath(path);
1181 if (rec != null) {
1182 rec.lastBenchMillis = System.currentTimeMillis();
1183 writeSettingsLocked();
1184 }
1185
1186 break;
1187 }
1188 case VoldResponseCode.TRIM_RESULT: {
1189 if (cooked.length != 4) break;
1190 final String path = cooked[1];
1191 final long bytes = Long.parseLong(cooked[2]);
1192 final long time = Long.parseLong(cooked[3]);
1193
1194 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
1195 dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path)
1196 + " " + bytes + " " + time);
1197
1198 final VolumeRecord rec = findRecordForPath(path);
1199 if (rec != null) {
1200 rec.lastTrimMillis = System.currentTimeMillis();
1201 writeSettingsLocked();
1202 }
1203
Jeff Sharkey9756d752015-05-14 21:07:42 -07001204 break;
1205 }
1206
Jeff Sharkey48877892015-03-18 11:27:19 -07001207 default: {
1208 Slog.d(TAG, "Unhandled vold event " + code);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001209 }
San Mehat4270e1e2010-01-29 05:32:19 -08001210 }
1211
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001212 return true;
San Mehat4270e1e2010-01-29 05:32:19 -08001213 }
1214
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001215 private void onDiskScannedLocked(DiskInfo disk) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001216 int volumeCount = 0;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001217 for (int i = 0; i < mVolumes.size(); i++) {
1218 final VolumeInfo vol = mVolumes.valueAt(i);
1219 if (Objects.equals(disk.id, vol.getDiskId())) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001220 volumeCount++;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001221 }
1222 }
1223
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001224 final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
1225 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1226 intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
1227 intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001228 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001229
1230 final CountDownLatch latch = mDiskScanLatches.remove(disk.id);
1231 if (latch != null) {
1232 latch.countDown();
1233 }
1234
Jeff Sharkeyf5a6bd72015-05-19 14:42:38 -07001235 disk.volumeCount = volumeCount;
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001236 mCallbacks.notifyDiskScanned(disk, volumeCount);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001237 }
1238
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001239 private void onVolumeCreatedLocked(VolumeInfo vol) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001240 if (vol.type == VolumeInfo.TYPE_EMULATED) {
1241 final StorageManager storage = mContext.getSystemService(StorageManager.class);
1242 final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
1243
1244 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
1245 && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
1246 Slog.v(TAG, "Found primary storage at " + vol);
1247 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1248 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1249 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1250
1251 } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
1252 Slog.v(TAG, "Found primary storage at " + vol);
1253 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1254 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1255 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1256 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001257
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001258 } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001259 // TODO: only look at first public partition
1260 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1261 && vol.disk.isDefaultPrimary()) {
1262 Slog.v(TAG, "Found primary storage at " + vol);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001263 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1264 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
San Mehat4270e1e2010-01-29 05:32:19 -08001265 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001266
1267 // Adoptable public disks are visible to apps, since they meet
1268 // public API requirement of being in a stable location.
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001269 if (vol.disk.isAdoptable()) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001270 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1271 }
1272
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07001273 vol.mountUserId = ActivityManager.getCurrentUser();
Jeff Sharkey48877892015-03-18 11:27:19 -07001274 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001275
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001276 } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1277 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1278
San Mehat4270e1e2010-01-29 05:32:19 -08001279 } else {
Jeff Sharkey48877892015-03-18 11:27:19 -07001280 Slog.d(TAG, "Skipping automatic mounting of " + vol);
San Mehat4270e1e2010-01-29 05:32:19 -08001281 }
1282 }
1283
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001284 private boolean isBroadcastWorthy(VolumeInfo vol) {
1285 switch (vol.getType()) {
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001286 case VolumeInfo.TYPE_PRIVATE:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001287 case VolumeInfo.TYPE_PUBLIC:
1288 case VolumeInfo.TYPE_EMULATED:
1289 break;
1290 default:
1291 return false;
1292 }
1293
1294 switch (vol.getState()) {
1295 case VolumeInfo.STATE_MOUNTED:
1296 case VolumeInfo.STATE_MOUNTED_READ_ONLY:
1297 case VolumeInfo.STATE_EJECTING:
1298 case VolumeInfo.STATE_UNMOUNTED:
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001299 case VolumeInfo.STATE_UNMOUNTABLE:
Tony Mantlerf0d71052015-06-24 11:45:25 -07001300 case VolumeInfo.STATE_BAD_REMOVAL:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001301 break;
1302 default:
1303 return false;
1304 }
1305
1306 return true;
1307 }
1308
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001309 private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001310 // Remember that we saw this volume so we're ready to accept user
1311 // metadata, or so we can annoy them when a private volume is ejected
1312 if (vol.isMountedReadable() && !TextUtils.isEmpty(vol.fsUuid)) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001313 VolumeRecord rec = mRecords.get(vol.fsUuid);
1314 if (rec == null) {
1315 rec = new VolumeRecord(vol.type, vol.fsUuid);
1316 rec.partGuid = vol.partGuid;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001317 rec.createdMillis = System.currentTimeMillis();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001318 if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1319 rec.nickname = vol.disk.getDescription();
1320 }
1321 mRecords.put(rec.fsUuid, rec);
1322 writeSettingsLocked();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001323 } else {
1324 // Handle upgrade case where we didn't store partition GUID
1325 if (TextUtils.isEmpty(rec.partGuid)) {
1326 rec.partGuid = vol.partGuid;
1327 writeSettingsLocked();
1328 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001329 }
1330 }
1331
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001332 mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
1333
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001334 // Do not broadcast before boot has completed to avoid launching the
1335 // processes that receive the intent unnecessarily.
1336 if (mBootCompleted && isBroadcastWorthy(vol)) {
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001337 final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001338 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
1339 intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
Tony Mantlerf0d71052015-06-24 11:45:25 -07001340 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001341 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001342 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001343 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001344
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001345 final String oldStateEnv = VolumeInfo.getEnvironmentForState(oldState);
1346 final String newStateEnv = VolumeInfo.getEnvironmentForState(newState);
Emily Bernier92aa5a22014-07-07 10:11:48 -04001347
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001348 if (!Objects.equals(oldStateEnv, newStateEnv)) {
1349 // Kick state changed event towards all started users. Any users
1350 // started after this point will trigger additional
1351 // user-specific broadcasts.
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001352 for (int userId : mSystemUnlockedUsers) {
Jeff Sharkey46349872015-07-28 10:49:47 -07001353 if (vol.isVisibleForRead(userId)) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001354 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001355 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey48877892015-03-18 11:27:19 -07001356
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001357 mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
1358 newStateEnv);
San Mehat4270e1e2010-01-29 05:32:19 -08001359 }
1360 }
1361 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001362
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001363 if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.state == VolumeInfo.STATE_EJECTING) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001364 // TODO: this should eventually be handled by new ObbVolume state changes
1365 /*
1366 * Some OBBs might have been unmounted when this volume was
1367 * unmounted, so send a message to the handler to let it know to
1368 * remove those from the list of mounted OBBS.
1369 */
1370 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
1371 OBB_FLUSH_MOUNT_STATE, vol.path));
1372 }
San Mehat4270e1e2010-01-29 05:32:19 -08001373 }
1374
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001375 private void onMoveStatusLocked(int status) {
1376 if (mMoveCallback == null) {
1377 Slog.w(TAG, "Odd, status but no move requested");
1378 return;
1379 }
1380
1381 // TODO: estimate remaining time
1382 try {
Jeff Sharkey50a05452015-04-29 11:24:52 -07001383 mMoveCallback.onStatusChanged(-1, status, -1);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001384 } catch (RemoteException ignored) {
1385 }
1386
1387 // We've finished copying and we're about to clean up old data, so
1388 // remember that move was successful if we get rebooted
1389 if (status == MOVE_STATUS_COPY_FINISHED) {
1390 Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
1391
1392 mPrimaryStorageUuid = mMoveTargetUuid;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001393 writeSettingsLocked();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001394 }
1395
1396 if (PackageManager.isMoveStatusFinished(status)) {
1397 Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status);
1398
1399 mMoveCallback = null;
1400 mMoveTargetUuid = null;
1401 }
1402 }
1403
Jeff Sharkey48877892015-03-18 11:27:19 -07001404 private void enforcePermission(String perm) {
1405 mContext.enforceCallingOrSelfPermission(perm, perm);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001406 }
1407
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001408 /**
1409 * Decide if volume is mountable per device policies.
1410 */
1411 private boolean isMountDisallowed(VolumeInfo vol) {
1412 if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
1413 final UserManager userManager = mContext.getSystemService(UserManager.class);
1414 return userManager.hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
1415 Binder.getCallingUserHandle());
1416 } else {
1417 return false;
Emily Bernier92aa5a22014-07-07 10:11:48 -04001418 }
1419 }
1420
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001421 private void enforceAdminUser() {
1422 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1423 final int callingUserId = UserHandle.getCallingUserId();
1424 boolean isAdmin;
1425 long token = Binder.clearCallingIdentity();
1426 try {
1427 isAdmin = um.getUserInfo(callingUserId).isAdmin();
1428 } finally {
1429 Binder.restoreCallingIdentity(token);
1430 }
1431 if (!isAdmin) {
1432 throw new SecurityException("Only admin users can adopt sd cards");
1433 }
1434 }
1435
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001436 /**
San Mehat207e5382010-02-04 20:46:54 -08001437 * Constructs a new MountService instance
1438 *
1439 * @param context Binder context for this service
1440 */
1441 public MountService(Context context) {
Christopher Tated417d622013-08-19 16:14:25 -07001442 sSelf = this;
1443
San Mehat207e5382010-02-04 20:46:54 -08001444 mContext = context;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001445 mCallbacks = new Callbacks(FgThread.get().getLooper());
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001446 mLockPatternUtils = new LockPatternUtils(mContext);
San Mehat207e5382010-02-04 20:46:54 -08001447
San Mehat207e5382010-02-04 20:46:54 -08001448 // XXX: This will go away soon in favor of IMountServiceObserver
1449 mPms = (PackageManagerService) ServiceManager.getService("package");
1450
Dianne Hackbornefa92b22013-05-03 14:11:43 -07001451 HandlerThread hthread = new HandlerThread(TAG);
1452 hthread.start();
1453 mHandler = new MountServiceHandler(hthread.getLooper());
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001454
Kenny Roota02b8b02010-08-05 16:14:17 -07001455 // Add OBB Action Handler to MountService thread.
Dianne Hackborn8d044e82013-04-30 17:24:15 -07001456 mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
Kenny Roota02b8b02010-08-05 16:14:17 -07001457
Christopher Tate7265abe2014-11-21 13:54:45 -08001458 // Initialize the last-fstrim tracking if necessary
1459 File dataDir = Environment.getDataDirectory();
1460 File systemDir = new File(dataDir, "system");
1461 mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
1462 if (!mLastMaintenanceFile.exists()) {
1463 // Not setting mLastMaintenance here means that we will force an
1464 // fstrim during reboot following the OTA that installs this code.
1465 try {
1466 (new FileOutputStream(mLastMaintenanceFile)).close();
1467 } catch (IOException e) {
1468 Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
1469 }
1470 } else {
1471 mLastMaintenance = mLastMaintenanceFile.lastModified();
1472 }
1473
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001474 mSettingsFile = new AtomicFile(
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001475 new File(Environment.getSystemSecureDirectory(), "storage.xml"));
1476
1477 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001478 readSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001479 }
1480
Svet Ganov6ee871e2015-07-10 14:29:33 -07001481 LocalServices.addService(MountServiceInternal.class, mMountServiceInternal);
1482
Marco Nelissenc34ebce2010-02-18 13:39:41 -08001483 /*
Kenny Root305bcbf2010-09-03 07:56:38 -07001484 * Create the connection to vold with a maximum queue of twice the
1485 * amount of containers we'd ever expect to have. This keeps an
1486 * "asec list" from blocking a thread repeatedly.
1487 */
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001488
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001489 mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
1490 null);
Jeff Sharkey48877892015-03-18 11:27:19 -07001491 mConnector.setDebug(true);
Jeff Sharkey8948c012015-11-03 12:33:54 -08001492 mConnector.setWarnIfHeld(mLock);
Kenny Root51a573c2012-05-17 13:30:28 -07001493
Kenny Root305bcbf2010-09-03 07:56:38 -07001494 Thread thread = new Thread(mConnector, VOLD_TAG);
San Mehat207e5382010-02-04 20:46:54 -08001495 thread.start();
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07001496
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001497 // Reuse parameters from first connector since they are tested and safe
1498 mCryptConnector = new NativeDaemonConnector(this, "cryptd",
1499 MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
1500 mCryptConnector.setDebug(true);
1501
1502 Thread crypt_thread = new Thread(mCryptConnector, CRYPTD_TAG);
1503 crypt_thread.start();
1504
Jeff Sharkeybcd262d2015-06-10 09:41:17 -07001505 final IntentFilter userFilter = new IntentFilter();
1506 userFilter.addAction(Intent.ACTION_USER_ADDED);
1507 userFilter.addAction(Intent.ACTION_USER_REMOVED);
1508 mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
1509
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001510 synchronized (mLock) {
1511 addInternalVolumeLocked();
1512 }
Amith Yamasania7892482015-08-07 11:09:05 -07001513
Kenny Root07714d42011-08-17 17:49:28 -07001514 // Add ourself to the Watchdog monitors if enabled.
1515 if (WATCHDOG_ENABLE) {
1516 Watchdog.getInstance().addMonitor(this);
1517 }
San Mehat207e5382010-02-04 20:46:54 -08001518 }
1519
Jeff Sharkey56e62932015-03-21 20:41:00 -07001520 private void systemReady() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001521 mSystemReady = true;
1522 mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
1523 }
1524
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001525 private void bootCompleted() {
1526 mBootCompleted = true;
1527 }
1528
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001529 private String getDefaultPrimaryStorageUuid() {
1530 if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) {
1531 return StorageManager.UUID_PRIMARY_PHYSICAL;
1532 } else {
1533 return StorageManager.UUID_PRIVATE_INTERNAL;
1534 }
1535 }
1536
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001537 private void readSettingsLocked() {
1538 mRecords.clear();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001539 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001540 mForceAdoptable = false;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001541
1542 FileInputStream fis = null;
1543 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001544 fis = mSettingsFile.openRead();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001545 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001546 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001547
1548 int type;
1549 while ((type = in.next()) != END_DOCUMENT) {
1550 if (type == START_TAG) {
1551 final String tag = in.getName();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001552 if (TAG_VOLUMES.equals(tag)) {
1553 final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001554 final boolean primaryPhysical = SystemProperties.getBoolean(
1555 StorageManager.PROP_PRIMARY_PHYSICAL, false);
1556 final boolean validAttr = (version >= VERSION_FIX_PRIMARY)
1557 || (version >= VERSION_ADD_PRIMARY && !primaryPhysical);
1558 if (validAttr) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001559 mPrimaryStorageUuid = readStringAttribute(in,
1560 ATTR_PRIMARY_STORAGE_UUID);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001561 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001562 mForceAdoptable = readBooleanAttribute(in, ATTR_FORCE_ADOPTABLE, false);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001563
1564 } else if (TAG_VOLUME.equals(tag)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001565 final VolumeRecord rec = readVolumeRecord(in);
1566 mRecords.put(rec.fsUuid, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001567 }
1568 }
1569 }
1570 } catch (FileNotFoundException e) {
1571 // Missing metadata is okay, probably first boot
1572 } catch (IOException e) {
1573 Slog.wtf(TAG, "Failed reading metadata", e);
1574 } catch (XmlPullParserException e) {
1575 Slog.wtf(TAG, "Failed reading metadata", e);
1576 } finally {
1577 IoUtils.closeQuietly(fis);
1578 }
1579 }
1580
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001581 private void writeSettingsLocked() {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001582 FileOutputStream fos = null;
1583 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001584 fos = mSettingsFile.startWrite();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001585
1586 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001587 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001588 out.startDocument(null, true);
1589 out.startTag(null, TAG_VOLUMES);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001590 writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001591 writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001592 writeBooleanAttribute(out, ATTR_FORCE_ADOPTABLE, mForceAdoptable);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001593 final int size = mRecords.size();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001594 for (int i = 0; i < size; i++) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001595 final VolumeRecord rec = mRecords.valueAt(i);
1596 writeVolumeRecord(out, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001597 }
1598 out.endTag(null, TAG_VOLUMES);
1599 out.endDocument();
1600
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001601 mSettingsFile.finishWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001602 } catch (IOException e) {
1603 if (fos != null) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001604 mSettingsFile.failWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001605 }
1606 }
1607 }
1608
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001609 public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
1610 final int type = readIntAttribute(in, ATTR_TYPE);
1611 final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
1612 final VolumeRecord meta = new VolumeRecord(type, fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001613 meta.partGuid = readStringAttribute(in, ATTR_PART_GUID);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001614 meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
1615 meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001616 meta.createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
1617 meta.lastTrimMillis = readLongAttribute(in, ATTR_LAST_TRIM_MILLIS);
1618 meta.lastBenchMillis = readLongAttribute(in, ATTR_LAST_BENCH_MILLIS);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001619 return meta;
1620 }
1621
1622 public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
1623 out.startTag(null, TAG_VOLUME);
1624 writeIntAttribute(out, ATTR_TYPE, rec.type);
1625 writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001626 writeStringAttribute(out, ATTR_PART_GUID, rec.partGuid);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001627 writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
1628 writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001629 writeLongAttribute(out, ATTR_CREATED_MILLIS, rec.createdMillis);
1630 writeLongAttribute(out, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
1631 writeLongAttribute(out, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001632 out.endTag(null, TAG_VOLUME);
1633 }
1634
San Mehat207e5382010-02-04 20:46:54 -08001635 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001636 * Exposed API calls below here
1637 */
1638
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001639 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001640 public void registerListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001641 mCallbacks.register(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001642 }
1643
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001644 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001645 public void unregisterListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001646 mCallbacks.unregister(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001647 }
1648
Jeff Sharkey48877892015-03-18 11:27:19 -07001649 @Override
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -08001650 public void shutdown(final IMountShutdownObserver observer) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001651 enforcePermission(android.Manifest.permission.SHUTDOWN);
San Mehat4270e1e2010-01-29 05:32:19 -08001652
San Mehata5078592010-03-25 09:36:54 -07001653 Slog.i(TAG, "Shutting down");
Jeff Sharkey48877892015-03-18 11:27:19 -07001654 mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001655 }
1656
Jeff Sharkey48877892015-03-18 11:27:19 -07001657 @Override
San Mehatb1043402010-02-05 08:26:50 -08001658 public boolean isUsbMassStorageConnected() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001659 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001660 }
1661
Jeff Sharkey48877892015-03-18 11:27:19 -07001662 @Override
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -08001663 public void setUsbMassStorageEnabled(boolean enable) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001664 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001665 }
1666
Jeff Sharkey48877892015-03-18 11:27:19 -07001667 @Override
San Mehatb1043402010-02-05 08:26:50 -08001668 public boolean isUsbMassStorageEnabled() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001669 throw new UnsupportedOperationException();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001670 }
Jason parks9ed98bc2011-01-17 09:58:35 -06001671
Jeff Sharkey48877892015-03-18 11:27:19 -07001672 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001673 public String getVolumeState(String mountPoint) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001674 throw new UnsupportedOperationException();
San Mehat7fd0fee2009-12-17 07:12:23 -08001675 }
1676
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001677 @Override
Kenny Roote1ff2142010-10-12 11:20:01 -07001678 public boolean isExternalStorageEmulated() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001679 throw new UnsupportedOperationException();
Kenny Roote1ff2142010-10-12 11:20:01 -07001680 }
1681
Jeff Sharkey48877892015-03-18 11:27:19 -07001682 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001683 public int mountVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001684 mount(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001685 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001686 }
1687
Jeff Sharkey48877892015-03-18 11:27:19 -07001688 @Override
Ben Komalo13c71972011-09-07 16:35:56 -07001689 public void unmountVolume(String path, boolean force, boolean removeEncryption) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001690 unmount(findVolumeIdForPathOrThrow(path));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 }
1692
Jeff Sharkey48877892015-03-18 11:27:19 -07001693 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001694 public int formatVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001695 format(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001696 return 0;
1697 }
1698
1699 @Override
1700 public void mount(String volId) {
1701 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1702 waitForReady();
1703
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001704 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001705 if (isMountDisallowed(vol)) {
1706 throw new SecurityException("Mounting " + volId + " restricted by policy");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001707 }
1708 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001709 mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001710 } catch (NativeDaemonConnectorException e) {
1711 throw e.rethrowAsParcelableException();
1712 }
1713 }
1714
1715 @Override
1716 public void unmount(String volId) {
1717 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1718 waitForReady();
1719
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001720 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001721
1722 // TODO: expand PMS to know about multiple volumes
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001723 if (vol.isPrimaryPhysical()) {
1724 final long ident = Binder.clearCallingIdentity();
1725 try {
1726 synchronized (mUnmountLock) {
1727 mUnmountSignal = new CountDownLatch(1);
1728 mPms.updateExternalMediaStatus(false, true);
1729 waitForLatch(mUnmountSignal, "mUnmountSignal");
1730 mUnmountSignal = null;
1731 }
1732 } finally {
1733 Binder.restoreCallingIdentity(ident);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001734 }
1735 }
1736
1737 try {
1738 mConnector.execute("volume", "unmount", vol.id);
1739 } catch (NativeDaemonConnectorException e) {
1740 throw e.rethrowAsParcelableException();
1741 }
1742 }
1743
1744 @Override
1745 public void format(String volId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001746 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -08001747 waitForReady();
San Mehat5b77dab2010-01-26 13:28:50 -08001748
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001749 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001750 try {
Jeff Sharkey4e83cc92015-05-27 14:38:39 -07001751 mConnector.execute("volume", "format", vol.id, "auto");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001752 } catch (NativeDaemonConnectorException e) {
1753 throw e.rethrowAsParcelableException();
Jeff Sharkey48877892015-03-18 11:27:19 -07001754 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001755 }
1756
1757 @Override
Jeff Sharkey9756d752015-05-14 21:07:42 -07001758 public long benchmark(String volId) {
1759 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1760 waitForReady();
1761
1762 try {
Jeff Sharkey14cbe522015-07-08 14:06:37 -07001763 // TODO: make benchmark async so we don't block other commands
1764 final NativeDaemonEvent res = mConnector.execute(3 * DateUtils.MINUTE_IN_MILLIS,
1765 "volume", "benchmark", volId);
Jeff Sharkey9756d752015-05-14 21:07:42 -07001766 return Long.parseLong(res.getMessage());
Todd Kennedy8101ee62015-06-23 13:35:28 -07001767 } catch (NativeDaemonTimeoutException e) {
1768 return Long.MAX_VALUE;
Jeff Sharkey9756d752015-05-14 21:07:42 -07001769 } catch (NativeDaemonConnectorException e) {
1770 throw e.rethrowAsParcelableException();
1771 }
1772 }
1773
1774 @Override
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001775 public void partitionPublic(String diskId) {
1776 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1777 waitForReady();
1778
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001779 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001780 try {
1781 mConnector.execute("volume", "partition", diskId, "public");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001782 waitForLatch(latch, "partitionPublic", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001783 } catch (NativeDaemonConnectorException e) {
1784 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001785 } catch (TimeoutException e) {
1786 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001787 }
1788 }
1789
1790 @Override
1791 public void partitionPrivate(String diskId) {
1792 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001793 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001794 waitForReady();
1795
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001796 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001797 try {
1798 mConnector.execute("volume", "partition", diskId, "private");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001799 waitForLatch(latch, "partitionPrivate", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001800 } catch (NativeDaemonConnectorException e) {
1801 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001802 } catch (TimeoutException e) {
1803 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001804 }
1805 }
1806
1807 @Override
1808 public void partitionMixed(String diskId, int ratio) {
1809 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001810 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001811 waitForReady();
1812
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001813 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001814 try {
1815 mConnector.execute("volume", "partition", diskId, "mixed", ratio);
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001816 waitForLatch(latch, "partitionMixed", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001817 } catch (NativeDaemonConnectorException e) {
1818 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001819 } catch (TimeoutException e) {
1820 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001821 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822 }
1823
Jeff Sharkey48877892015-03-18 11:27:19 -07001824 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001825 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001826 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1827 waitForReady();
1828
Jeff Sharkey50a05452015-04-29 11:24:52 -07001829 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001830 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001831 final VolumeRecord rec = mRecords.get(fsUuid);
1832 rec.nickname = nickname;
Jeff Sharkey50a05452015-04-29 11:24:52 -07001833 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001834 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001835 }
1836 }
1837
1838 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001839 public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001840 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1841 waitForReady();
1842
Jeff Sharkey50a05452015-04-29 11:24:52 -07001843 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001844 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001845 final VolumeRecord rec = mRecords.get(fsUuid);
1846 rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001847 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001848 writeSettingsLocked();
1849 }
1850 }
1851
1852 @Override
1853 public void forgetVolume(String fsUuid) {
1854 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1855 waitForReady();
1856
Jeff Sharkey50a05452015-04-29 11:24:52 -07001857 Preconditions.checkNotNull(fsUuid);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001858
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001859 synchronized (mLock) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001860 final VolumeRecord rec = mRecords.remove(fsUuid);
1861 if (rec != null && !TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001862 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001863 }
1864 mCallbacks.notifyVolumeForgotten(fsUuid);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001865
1866 // If this had been primary storage, revert back to internal and
1867 // reset vold so we bind into new volume into place.
1868 if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001869 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001870 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001871 }
1872
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001873 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001874 }
1875 }
1876
Jeff Sharkey7d2af542015-05-12 15:27:15 -07001877 @Override
1878 public void forgetAllVolumes() {
1879 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1880 waitForReady();
1881
Jeff Sharkey50a05452015-04-29 11:24:52 -07001882 synchronized (mLock) {
1883 for (int i = 0; i < mRecords.size(); i++) {
1884 final String fsUuid = mRecords.keyAt(i);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001885 final VolumeRecord rec = mRecords.valueAt(i);
1886 if (!TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001887 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001888 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001889 mCallbacks.notifyVolumeForgotten(fsUuid);
1890 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001891 mRecords.clear();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001892
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001893 if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)) {
1894 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
1895 }
1896
1897 writeSettingsLocked();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001898 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001899 }
1900 }
1901
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001902 private void forgetPartition(String partGuid) {
1903 try {
1904 mConnector.execute("volume", "forget_partition", partGuid);
1905 } catch (NativeDaemonConnectorException e) {
1906 Slog.w(TAG, "Failed to forget key for " + partGuid + ": " + e);
1907 }
1908 }
1909
Svet Ganov6ee871e2015-07-10 14:29:33 -07001910 private void remountUidExternalStorage(int uid, int mode) {
Jeff Sharkey9527b222015-06-24 15:24:48 -07001911 waitForReady();
1912
Svet Ganov6ee871e2015-07-10 14:29:33 -07001913 String modeName = "none";
1914 switch (mode) {
1915 case Zygote.MOUNT_EXTERNAL_DEFAULT: {
1916 modeName = "default";
1917 } break;
1918
1919 case Zygote.MOUNT_EXTERNAL_READ: {
1920 modeName = "read";
1921 } break;
1922
1923 case Zygote.MOUNT_EXTERNAL_WRITE: {
1924 modeName = "write";
1925 } break;
Jeff Sharkey9527b222015-06-24 15:24:48 -07001926 }
1927
1928 try {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001929 mConnector.execute("volume", "remount_uid", uid, modeName);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001930 } catch (NativeDaemonConnectorException e) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001931 Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001932 }
1933 }
1934
1935 @Override
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001936 public void setDebugFlags(int flags, int mask) {
1937 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1938 waitForReady();
1939
Jeff Sharkeyba512352015-11-12 20:17:45 -08001940 if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001941 if (StorageManager.isNativeFileBasedEncryptionEnabled()) {
1942 throw new IllegalStateException(
1943 "Emulation not available on device with native FBE");
1944 }
1945
Jeff Sharkeyba512352015-11-12 20:17:45 -08001946 final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
1947 SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001948
1949 // Perform hard reboot to kick policy into place
1950 mContext.getSystemService(PowerManager.class).reboot(null);
Jeff Sharkeyba512352015-11-12 20:17:45 -08001951 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001952
Jeff Sharkeyba512352015-11-12 20:17:45 -08001953 if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
1954 synchronized (mLock) {
1955 mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
1956
1957 writeSettingsLocked();
1958 mHandler.obtainMessage(H_RESET).sendToTarget();
1959 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001960 }
1961 }
1962
1963 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001964 public String getPrimaryStorageUuid() {
1965 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1966 waitForReady();
1967
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001968 synchronized (mLock) {
1969 return mPrimaryStorageUuid;
1970 }
1971 }
1972
1973 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001974 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
1975 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1976 waitForReady();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001977
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001978 synchronized (mLock) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001979 if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) {
1980 throw new IllegalArgumentException("Primary storage already at " + volumeUuid);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001981 }
1982
1983 if (mMoveCallback != null) {
1984 throw new IllegalStateException("Move already in progress");
1985 }
1986 mMoveCallback = callback;
1987 mMoveTargetUuid = volumeUuid;
1988
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001989 // When moving to/from primary physical volume, we probably just nuked
1990 // the current storage location, so we have nothing to move.
1991 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1992 || Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
1993 Slog.d(TAG, "Skipping move to/from primary physical");
1994 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
1995 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001996 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001997
1998 } else {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001999 final VolumeInfo from = findStorageForUuid(mPrimaryStorageUuid);
2000 final VolumeInfo to = findStorageForUuid(volumeUuid);
2001
2002 if (from == null) {
2003 Slog.w(TAG, "Failing move due to missing from volume " + mPrimaryStorageUuid);
2004 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2005 return;
2006 } else if (to == null) {
2007 Slog.w(TAG, "Failing move due to missing to volume " + volumeUuid);
2008 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2009 return;
2010 }
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002011
2012 try {
2013 mConnector.execute("volume", "move_storage", from.id, to.id);
2014 } catch (NativeDaemonConnectorException e) {
2015 throw e.rethrowAsParcelableException();
2016 }
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002017 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002018 }
2019 }
2020
2021 @Override
Mike Lockwoodecedfdc2011-06-08 15:11:59 -07002022 public int[] getStorageUsers(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002023 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehatc1b4ce92010-02-16 17:13:03 -08002024 waitForReady();
2025 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002026 final String[] r = NativeDaemonEvent.filterMessageList(
2027 mConnector.executeForList("storage", "users", path),
2028 VoldResponseCode.StorageUsersListResult);
2029
San Mehatc1b4ce92010-02-16 17:13:03 -08002030 // FMT: <pid> <process name>
2031 int[] data = new int[r.length];
2032 for (int i = 0; i < r.length; i++) {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002033 String[] tok = r[i].split(" ");
San Mehatc1b4ce92010-02-16 17:13:03 -08002034 try {
2035 data[i] = Integer.parseInt(tok[0]);
2036 } catch (NumberFormatException nfe) {
San Mehata5078592010-03-25 09:36:54 -07002037 Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
San Mehatc1b4ce92010-02-16 17:13:03 -08002038 return new int[0];
2039 }
2040 }
2041 return data;
2042 } catch (NativeDaemonConnectorException e) {
San Mehata5078592010-03-25 09:36:54 -07002043 Slog.e(TAG, "Failed to retrieve storage users list", e);
San Mehatc1b4ce92010-02-16 17:13:03 -08002044 return new int[0];
2045 }
2046 }
2047
San Mehatb1043402010-02-05 08:26:50 -08002048 private void warnOnNotMounted() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002049 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002050 for (int i = 0; i < mVolumes.size(); i++) {
2051 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07002052 if (vol.isPrimary() && vol.isMountedWritable()) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002053 // Cool beans, we have a mounted primary volume
2054 return;
2055 }
Jeff Sharkey32ee8312012-09-30 13:21:31 -07002056 }
San Mehatb1043402010-02-05 08:26:50 -08002057 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002058
2059 Slog.w(TAG, "No primary storage mounted!");
San Mehatb1043402010-02-05 08:26:50 -08002060 }
2061
San Mehat4270e1e2010-01-29 05:32:19 -08002062 public String[] getSecureContainerList() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002063 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002064 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002065 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002066
San Mehat4270e1e2010-01-29 05:32:19 -08002067 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002068 return NativeDaemonEvent.filterMessageList(
2069 mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
San Mehat4270e1e2010-01-29 05:32:19 -08002070 } catch (NativeDaemonConnectorException e) {
2071 return new String[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002072 }
2073 }
San Mehat36972292010-01-06 11:06:32 -08002074
Kenny Root6dceb882012-04-12 14:23:49 -07002075 public int createSecureContainer(String id, int sizeMb, String fstype, String key,
2076 int ownerUid, boolean external) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002077 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehat207e5382010-02-04 20:46:54 -08002078 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002079 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002080
San Mehatb1043402010-02-05 08:26:50 -08002081 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002082 try {
Jeff Sharkey56cd6462013-06-07 15:09:15 -07002083 mConnector.execute("asec", "create", id, sizeMb, fstype, new SensitiveArg(key),
2084 ownerUid, external ? "1" : "0");
San Mehat4270e1e2010-01-29 05:32:19 -08002085 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002086 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002087 }
San Mehata181b212010-02-11 06:50:20 -08002088
2089 if (rc == StorageResultCode.OperationSucceeded) {
2090 synchronized (mAsecMountSet) {
2091 mAsecMountSet.add(id);
2092 }
2093 }
San Mehat4270e1e2010-01-29 05:32:19 -08002094 return rc;
San Mehat36972292010-01-06 11:06:32 -08002095 }
2096
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002097 @Override
2098 public int resizeSecureContainer(String id, int sizeMb, String key) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002099 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002100 waitForReady();
2101 warnOnNotMounted();
2102
2103 int rc = StorageResultCode.OperationSucceeded;
2104 try {
2105 mConnector.execute("asec", "resize", id, sizeMb, new SensitiveArg(key));
2106 } catch (NativeDaemonConnectorException e) {
2107 rc = StorageResultCode.OperationFailedInternalError;
2108 }
2109 return rc;
2110 }
2111
San Mehat4270e1e2010-01-29 05:32:19 -08002112 public int finalizeSecureContainer(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002113 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehatb1043402010-02-05 08:26:50 -08002114 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002115
San Mehatb1043402010-02-05 08:26:50 -08002116 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002117 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002118 mConnector.execute("asec", "finalize", id);
San Mehata181b212010-02-11 06:50:20 -08002119 /*
2120 * Finalization does a remount, so no need
2121 * to update mAsecMountSet
2122 */
San Mehat4270e1e2010-01-29 05:32:19 -08002123 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002124 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002125 }
San Mehat4270e1e2010-01-29 05:32:19 -08002126 return rc;
San Mehat36972292010-01-06 11:06:32 -08002127 }
2128
Kenny Root6dceb882012-04-12 14:23:49 -07002129 public int fixPermissionsSecureContainer(String id, int gid, String filename) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002130 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Kenny Root6dceb882012-04-12 14:23:49 -07002131 warnOnNotMounted();
2132
2133 int rc = StorageResultCode.OperationSucceeded;
2134 try {
2135 mConnector.execute("asec", "fixperms", id, gid, filename);
2136 /*
2137 * Fix permissions does a remount, so no need to update
2138 * mAsecMountSet
2139 */
2140 } catch (NativeDaemonConnectorException e) {
2141 rc = StorageResultCode.OperationFailedInternalError;
2142 }
2143 return rc;
2144 }
2145
San Mehatd9709982010-02-18 11:43:03 -08002146 public int destroySecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002147 enforcePermission(android.Manifest.permission.ASEC_DESTROY);
San Mehat207e5382010-02-04 20:46:54 -08002148 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002149 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002150
Kenny Rootaa485402010-09-14 14:49:41 -07002151 /*
2152 * Force a GC to make sure AssetManagers in other threads of the
2153 * system_server are cleaned up. We have to do this since AssetManager
2154 * instances are kept as a WeakReference and it's possible we have files
2155 * open on the external storage.
2156 */
2157 Runtime.getRuntime().gc();
2158
San Mehatb1043402010-02-05 08:26:50 -08002159 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002160 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002161 final Command cmd = new Command("asec", "destroy", id);
2162 if (force) {
2163 cmd.appendArg("force");
2164 }
2165 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002166 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002167 int code = e.getCode();
2168 if (code == VoldResponseCode.OpFailedStorageBusy) {
2169 rc = StorageResultCode.OperationFailedStorageBusy;
2170 } else {
2171 rc = StorageResultCode.OperationFailedInternalError;
2172 }
San Mehat02735bc2010-01-26 15:18:08 -08002173 }
San Mehata181b212010-02-11 06:50:20 -08002174
2175 if (rc == StorageResultCode.OperationSucceeded) {
2176 synchronized (mAsecMountSet) {
2177 if (mAsecMountSet.contains(id)) {
2178 mAsecMountSet.remove(id);
2179 }
2180 }
2181 }
2182
San Mehat4270e1e2010-01-29 05:32:19 -08002183 return rc;
San Mehat36972292010-01-06 11:06:32 -08002184 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002185
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002186 public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002187 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002188 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002189 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002190
San Mehata181b212010-02-11 06:50:20 -08002191 synchronized (mAsecMountSet) {
2192 if (mAsecMountSet.contains(id)) {
2193 return StorageResultCode.OperationFailedStorageMounted;
2194 }
2195 }
2196
San Mehatb1043402010-02-05 08:26:50 -08002197 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002198 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002199 mConnector.execute("asec", "mount", id, new SensitiveArg(key), ownerUid,
2200 readOnly ? "ro" : "rw");
San Mehat4270e1e2010-01-29 05:32:19 -08002201 } catch (NativeDaemonConnectorException e) {
Kenny Rootf0304622010-03-19 19:20:42 -07002202 int code = e.getCode();
2203 if (code != VoldResponseCode.OpFailedStorageBusy) {
2204 rc = StorageResultCode.OperationFailedInternalError;
2205 }
San Mehat02735bc2010-01-26 15:18:08 -08002206 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002207
2208 if (rc == StorageResultCode.OperationSucceeded) {
2209 synchronized (mAsecMountSet) {
2210 mAsecMountSet.add(id);
2211 }
2212 }
San Mehat4270e1e2010-01-29 05:32:19 -08002213 return rc;
San Mehat36972292010-01-06 11:06:32 -08002214 }
2215
San Mehatd9709982010-02-18 11:43:03 -08002216 public int unmountSecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002217 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002218 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002219 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002220
San Mehat6cdd9c02010-02-09 14:45:20 -08002221 synchronized (mAsecMountSet) {
2222 if (!mAsecMountSet.contains(id)) {
San Mehata181b212010-02-11 06:50:20 -08002223 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehat6cdd9c02010-02-09 14:45:20 -08002224 }
2225 }
2226
Kenny Rootaa485402010-09-14 14:49:41 -07002227 /*
2228 * Force a GC to make sure AssetManagers in other threads of the
2229 * system_server are cleaned up. We have to do this since AssetManager
2230 * instances are kept as a WeakReference and it's possible we have files
2231 * open on the external storage.
2232 */
2233 Runtime.getRuntime().gc();
2234
San Mehatb1043402010-02-05 08:26:50 -08002235 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002236 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002237 final Command cmd = new Command("asec", "unmount", id);
2238 if (force) {
2239 cmd.appendArg("force");
2240 }
2241 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002242 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002243 int code = e.getCode();
2244 if (code == VoldResponseCode.OpFailedStorageBusy) {
2245 rc = StorageResultCode.OperationFailedStorageBusy;
2246 } else {
2247 rc = StorageResultCode.OperationFailedInternalError;
2248 }
San Mehat02735bc2010-01-26 15:18:08 -08002249 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002250
2251 if (rc == StorageResultCode.OperationSucceeded) {
2252 synchronized (mAsecMountSet) {
2253 mAsecMountSet.remove(id);
2254 }
2255 }
San Mehat4270e1e2010-01-29 05:32:19 -08002256 return rc;
San Mehat9dba7092010-01-18 06:47:41 -08002257 }
2258
San Mehat6cdd9c02010-02-09 14:45:20 -08002259 public boolean isSecureContainerMounted(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002260 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat6cdd9c02010-02-09 14:45:20 -08002261 waitForReady();
2262 warnOnNotMounted();
2263
2264 synchronized (mAsecMountSet) {
2265 return mAsecMountSet.contains(id);
2266 }
2267 }
2268
San Mehat4270e1e2010-01-29 05:32:19 -08002269 public int renameSecureContainer(String oldId, String newId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002270 enforcePermission(android.Manifest.permission.ASEC_RENAME);
San Mehat207e5382010-02-04 20:46:54 -08002271 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002272 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002273
San Mehata181b212010-02-11 06:50:20 -08002274 synchronized (mAsecMountSet) {
San Mehat85451ee2010-02-24 08:54:18 -08002275 /*
Jason parks9ed98bc2011-01-17 09:58:35 -06002276 * Because a mounted container has active internal state which cannot be
San Mehat85451ee2010-02-24 08:54:18 -08002277 * changed while active, we must ensure both ids are not currently mounted.
2278 */
2279 if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
San Mehata181b212010-02-11 06:50:20 -08002280 return StorageResultCode.OperationFailedStorageMounted;
2281 }
2282 }
2283
San Mehatb1043402010-02-05 08:26:50 -08002284 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002285 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002286 mConnector.execute("asec", "rename", oldId, newId);
San Mehat4270e1e2010-01-29 05:32:19 -08002287 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002288 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002289 }
San Mehata181b212010-02-11 06:50:20 -08002290
San Mehat4270e1e2010-01-29 05:32:19 -08002291 return rc;
San Mehat45f61042010-01-23 08:12:43 -08002292 }
2293
San Mehat4270e1e2010-01-29 05:32:19 -08002294 public String getSecureContainerPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002295 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002296 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002297 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002298
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002299 final NativeDaemonEvent event;
San Mehat2d66cef2010-03-23 11:12:52 -07002300 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002301 event = mConnector.execute("asec", "path", id);
2302 event.checkCode(VoldResponseCode.AsecPathResult);
2303 return event.getMessage();
San Mehat2d66cef2010-03-23 11:12:52 -07002304 } catch (NativeDaemonConnectorException e) {
2305 int code = e.getCode();
2306 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Fredrik Helmera20c8ef2011-02-09 16:16:10 +01002307 Slog.i(TAG, String.format("Container '%s' not found", id));
2308 return null;
San Mehat22dd86e2010-01-12 12:21:18 -08002309 } else {
San Mehat2d66cef2010-03-23 11:12:52 -07002310 throw new IllegalStateException(String.format("Unexpected response code %d", code));
San Mehat22dd86e2010-01-12 12:21:18 -08002311 }
2312 }
San Mehat22dd86e2010-01-12 12:21:18 -08002313 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002314
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002315 public String getSecureContainerFilesystemPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002316 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002317 waitForReady();
2318 warnOnNotMounted();
2319
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002320 final NativeDaemonEvent event;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002321 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002322 event = mConnector.execute("asec", "fspath", id);
2323 event.checkCode(VoldResponseCode.AsecPathResult);
2324 return event.getMessage();
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002325 } catch (NativeDaemonConnectorException e) {
2326 int code = e.getCode();
2327 if (code == VoldResponseCode.OpFailedStorageNotFound) {
2328 Slog.i(TAG, String.format("Container '%s' not found", id));
2329 return null;
2330 } else {
2331 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2332 }
2333 }
2334 }
2335
Jeff Sharkey48877892015-03-18 11:27:19 -07002336 @Override
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002337 public void finishMediaUpdate() {
Jeff Sharkey9527b222015-06-24 15:24:48 -07002338 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
Rubin Xucd7a0142015-04-17 23:45:27 +01002339 throw new SecurityException("no permission to call finishMediaUpdate()");
2340 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002341 if (mUnmountSignal != null) {
2342 mUnmountSignal.countDown();
2343 } else {
2344 Slog.w(TAG, "Odd, nobody asked to unmount?");
2345 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002346 }
Kenny Root02c87302010-07-01 08:10:18 -07002347
Kenny Roota02b8b02010-08-05 16:14:17 -07002348 private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
2349 if (callerUid == android.os.Process.SYSTEM_UID) {
2350 return true;
2351 }
2352
Kenny Root02c87302010-07-01 08:10:18 -07002353 if (packageName == null) {
2354 return false;
2355 }
2356
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07002357 final int packageUid = mPms.getPackageUid(packageName, UserHandle.getUserId(callerUid));
Kenny Root02c87302010-07-01 08:10:18 -07002358
2359 if (DEBUG_OBB) {
2360 Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
2361 packageUid + ", callerUid = " + callerUid);
2362 }
2363
2364 return callerUid == packageUid;
2365 }
2366
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002367 public String getMountedObbPath(String rawPath) {
2368 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002369
Kenny Root02c87302010-07-01 08:10:18 -07002370 waitForReady();
2371 warnOnNotMounted();
2372
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002373 final ObbState state;
Rubin Xucd7a0142015-04-17 23:45:27 +01002374 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002375 state = mObbPathToStateMap.get(rawPath);
2376 }
2377 if (state == null) {
2378 Slog.w(TAG, "Failed to find OBB mounted at " + rawPath);
2379 return null;
2380 }
2381
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002382 final NativeDaemonEvent event;
Kenny Root02c87302010-07-01 08:10:18 -07002383 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07002384 event = mConnector.execute("obb", "path", state.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002385 event.checkCode(VoldResponseCode.AsecPathResult);
2386 return event.getMessage();
Kenny Root02c87302010-07-01 08:10:18 -07002387 } catch (NativeDaemonConnectorException e) {
2388 int code = e.getCode();
2389 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Kenny Roota02b8b02010-08-05 16:14:17 -07002390 return null;
Kenny Root02c87302010-07-01 08:10:18 -07002391 } else {
2392 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2393 }
2394 }
2395 }
2396
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002397 @Override
2398 public boolean isObbMounted(String rawPath) {
2399 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002400 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002401 return mObbPathToStateMap.containsKey(rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002402 }
Kenny Root02c87302010-07-01 08:10:18 -07002403 }
2404
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002405 @Override
2406 public void mountObb(
2407 String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) {
2408 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2409 Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
2410 Preconditions.checkNotNull(token, "token cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002411
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002412 final int callingUid = Binder.getCallingUid();
2413 final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce);
2414 final ObbAction action = new MountObbAction(obbState, key, callingUid);
Kenny Roota02b8b02010-08-05 16:14:17 -07002415 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
2416
2417 if (DEBUG_OBB)
2418 Slog.i(TAG, "Send to OBB handler: " + action.toString());
Kenny Root02c87302010-07-01 08:10:18 -07002419 }
2420
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002421 @Override
2422 public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
2423 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2424
2425 final ObbState existingState;
Rubin Xucd7a0142015-04-17 23:45:27 +01002426 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002427 existingState = mObbPathToStateMap.get(rawPath);
Kenny Rootf1121dc2010-09-29 07:30:53 -07002428 }
2429
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002430 if (existingState != null) {
2431 // TODO: separate state object from request data
2432 final int callingUid = Binder.getCallingUid();
2433 final ObbState newState = new ObbState(
2434 rawPath, existingState.canonicalPath, callingUid, token, nonce);
2435 final ObbAction action = new UnmountObbAction(newState, force);
2436 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root02c87302010-07-01 08:10:18 -07002437
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002438 if (DEBUG_OBB)
2439 Slog.i(TAG, "Send to OBB handler: " + action.toString());
2440 } else {
2441 Slog.w(TAG, "Unknown OBB mount at " + rawPath);
2442 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002443 }
2444
Ben Komalo444eca22011-09-01 15:17:44 -07002445 @Override
2446 public int getEncryptionState() {
2447 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2448 "no permission to access the crypt keeper");
2449
2450 waitForReady();
2451
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002452 final NativeDaemonEvent event;
Ben Komalo444eca22011-09-01 15:17:44 -07002453 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002454 event = mCryptConnector.execute("cryptfs", "cryptocomplete");
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002455 return Integer.parseInt(event.getMessage());
Ben Komalo444eca22011-09-01 15:17:44 -07002456 } catch (NumberFormatException e) {
2457 // Bad result - unexpected.
2458 Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
2459 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2460 } catch (NativeDaemonConnectorException e) {
2461 // Something bad happened.
2462 Slog.w(TAG, "Error in communicating with cryptfs in validating");
2463 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2464 }
2465 }
2466
2467 @Override
Jason parks5af0b912010-11-29 09:05:25 -06002468 public int decryptStorage(String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002469 if (TextUtils.isEmpty(password)) {
2470 throw new IllegalArgumentException("password cannot be empty");
Jason parks5af0b912010-11-29 09:05:25 -06002471 }
2472
Jason parks8888c592011-01-20 22:46:41 -06002473 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2474 "no permission to access the crypt keeper");
Jason parks5af0b912010-11-29 09:05:25 -06002475
2476 waitForReady();
2477
2478 if (DEBUG_EVENTS) {
2479 Slog.i(TAG, "decrypting storage...");
2480 }
2481
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002482 final NativeDaemonEvent event;
Jason parks5af0b912010-11-29 09:05:25 -06002483 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002484 event = mCryptConnector.execute("cryptfs", "checkpw", new SensitiveArg(password));
Jason parks9ed98bc2011-01-17 09:58:35 -06002485
Fredrik Roubertda6aedf2011-12-20 17:34:43 +01002486 final int code = Integer.parseInt(event.getMessage());
Jason parks9ed98bc2011-01-17 09:58:35 -06002487 if (code == 0) {
2488 // Decrypt was successful. Post a delayed message before restarting in order
2489 // to let the UI to clear itself
2490 mHandler.postDelayed(new Runnable() {
2491 public void run() {
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002492 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002493 mCryptConnector.execute("cryptfs", "restart");
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002494 } catch (NativeDaemonConnectorException e) {
2495 Slog.e(TAG, "problem executing in background", e);
2496 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002497 }
Jason parksf7b3cd42011-01-27 09:28:25 -06002498 }, 1000); // 1 second
Jason parks9ed98bc2011-01-17 09:58:35 -06002499 }
2500
2501 return code;
Jason parks5af0b912010-11-29 09:05:25 -06002502 } catch (NativeDaemonConnectorException e) {
2503 // Decryption failed
2504 return e.getCode();
2505 }
Jason parks5af0b912010-11-29 09:05:25 -06002506 }
2507
Paul Lawrence46791e72014-04-03 09:10:26 -07002508 public int encryptStorage(int type, String password) {
2509 if (TextUtils.isEmpty(password) && type != StorageManager.CRYPT_TYPE_DEFAULT) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002510 throw new IllegalArgumentException("password cannot be empty");
Jason parks56aa5322011-01-07 09:01:15 -06002511 }
2512
Jason parks8888c592011-01-20 22:46:41 -06002513 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2514 "no permission to access the crypt keeper");
Jason parks56aa5322011-01-07 09:01:15 -06002515
2516 waitForReady();
2517
2518 if (DEBUG_EVENTS) {
Jason parks8888c592011-01-20 22:46:41 -06002519 Slog.i(TAG, "encrypting storage...");
Jason parks56aa5322011-01-07 09:01:15 -06002520 }
2521
2522 try {
Paul Lawrence5096d9e2015-09-09 13:05:45 -07002523 if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
2524 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2525 CRYPTO_TYPES[type]);
2526 } else {
2527 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2528 CRYPTO_TYPES[type], new SensitiveArg(password));
2529 }
Jason parks56aa5322011-01-07 09:01:15 -06002530 } catch (NativeDaemonConnectorException e) {
2531 // Encryption failed
2532 return e.getCode();
2533 }
2534
2535 return 0;
2536 }
2537
Paul Lawrence8e397362014-01-27 15:22:30 -08002538 /** Set the password for encrypting the master key.
2539 * @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
2540 * @param password The password to set.
2541 */
2542 public int changeEncryptionPassword(int type, String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002543 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2544 "no permission to access the crypt keeper");
2545
2546 waitForReady();
2547
2548 if (DEBUG_EVENTS) {
2549 Slog.i(TAG, "changing encryption password...");
2550 }
2551
2552 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002553 NativeDaemonEvent event = mCryptConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type],
Paul Lawrence05487612015-06-09 13:35:38 -07002554 new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002555 return Integer.parseInt(event.getMessage());
Jason parksf7b3cd42011-01-27 09:28:25 -06002556 } catch (NativeDaemonConnectorException e) {
2557 // Encryption failed
2558 return e.getCode();
2559 }
2560 }
2561
Christopher Tate32418be2011-10-10 13:51:12 -07002562 /**
2563 * Validate a user-supplied password string with cryptfs
2564 */
2565 @Override
2566 public int verifyEncryptionPassword(String password) throws RemoteException {
2567 // Only the system process is permitted to validate passwords
2568 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2569 throw new SecurityException("no permission to access the crypt keeper");
2570 }
2571
2572 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2573 "no permission to access the crypt keeper");
2574
2575 if (TextUtils.isEmpty(password)) {
2576 throw new IllegalArgumentException("password cannot be empty");
2577 }
2578
2579 waitForReady();
2580
2581 if (DEBUG_EVENTS) {
2582 Slog.i(TAG, "validating encryption password...");
2583 }
2584
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002585 final NativeDaemonEvent event;
Christopher Tate32418be2011-10-10 13:51:12 -07002586 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002587 event = mCryptConnector.execute("cryptfs", "verifypw", new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002588 Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
2589 return Integer.parseInt(event.getMessage());
Christopher Tate32418be2011-10-10 13:51:12 -07002590 } catch (NativeDaemonConnectorException e) {
2591 // Encryption failed
2592 return e.getCode();
2593 }
2594 }
2595
Paul Lawrence8e397362014-01-27 15:22:30 -08002596 /**
2597 * Get the type of encryption used to encrypt the master key.
2598 * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
2599 */
2600 @Override
Svetoslav16e4a1a2014-09-29 18:16:20 -07002601 public int getPasswordType() {
Paul Lawrence8e397362014-01-27 15:22:30 -08002602
2603 waitForReady();
2604
2605 final NativeDaemonEvent event;
2606 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002607 event = mCryptConnector.execute("cryptfs", "getpwtype");
Paul Lawrence8e397362014-01-27 15:22:30 -08002608 for (int i = 0; i < CRYPTO_TYPES.length; ++i) {
2609 if (CRYPTO_TYPES[i].equals(event.getMessage()))
2610 return i;
2611 }
2612
2613 throw new IllegalStateException("unexpected return from cryptfs");
2614 } catch (NativeDaemonConnectorException e) {
2615 throw e.rethrowAsParcelableException();
2616 }
2617 }
2618
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002619 /**
2620 * Set a field in the crypto header.
2621 * @param field field to set
2622 * @param contents contents to set in field
2623 */
2624 @Override
2625 public void setField(String field, String contents) throws RemoteException {
2626
2627 waitForReady();
2628
2629 final NativeDaemonEvent event;
2630 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002631 event = mCryptConnector.execute("cryptfs", "setfield", field, contents);
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002632 } catch (NativeDaemonConnectorException e) {
2633 throw e.rethrowAsParcelableException();
2634 }
2635 }
2636
2637 /**
2638 * Gets a field from the crypto header.
2639 * @param field field to get
2640 * @return contents of field
2641 */
2642 @Override
2643 public String getField(String field) throws RemoteException {
2644
2645 waitForReady();
2646
2647 final NativeDaemonEvent event;
2648 try {
2649 final String[] contents = NativeDaemonEvent.filterMessageList(
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002650 mCryptConnector.executeForList("cryptfs", "getfield", field),
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002651 VoldResponseCode.CryptfsGetfieldResult);
2652 String result = new String();
2653 for (String content : contents) {
2654 result += content;
2655 }
2656 return result;
2657 } catch (NativeDaemonConnectorException e) {
2658 throw e.rethrowAsParcelableException();
2659 }
2660 }
2661
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002662 /**
2663 * Is userdata convertible to file based encryption?
2664 * @return non zero for convertible
2665 */
2666 @Override
2667 public boolean isConvertibleToFBE() throws RemoteException {
2668
2669 waitForReady();
2670
2671 final NativeDaemonEvent event;
2672 try {
2673 event = mCryptConnector.execute("cryptfs", "isConvertibleToFBE");
2674 return Integer.parseInt(event.getMessage()) != 0;
2675 } catch (NativeDaemonConnectorException e) {
2676 throw e.rethrowAsParcelableException();
2677 }
2678 }
2679
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002680 @Override
Paul Lawrence945490c2014-03-27 16:37:28 +00002681 public String getPassword() throws RemoteException {
Rubin Xucd7a0142015-04-17 23:45:27 +01002682 mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE,
2683 "only keyguard can retrieve password");
Paul Lawrence945490c2014-03-27 16:37:28 +00002684 if (!isReady()) {
2685 return new String();
2686 }
2687
2688 final NativeDaemonEvent event;
2689 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002690 event = mCryptConnector.execute("cryptfs", "getpw");
Paul Lawrence24063b52015-01-06 13:11:23 -08002691 if ("-1".equals(event.getMessage())) {
2692 // -1 equals no password
2693 return null;
2694 }
Paul Lawrence05487612015-06-09 13:35:38 -07002695 return event.getMessage();
Paul Lawrence945490c2014-03-27 16:37:28 +00002696 } catch (NativeDaemonConnectorException e) {
2697 throw e.rethrowAsParcelableException();
Paul Lawrence24063b52015-01-06 13:11:23 -08002698 } catch (IllegalArgumentException e) {
2699 Slog.e(TAG, "Invalid response to getPassword");
2700 return null;
Paul Lawrence945490c2014-03-27 16:37:28 +00002701 }
2702 }
2703
2704 @Override
2705 public void clearPassword() throws RemoteException {
2706 if (!isReady()) {
2707 return;
2708 }
2709
2710 final NativeDaemonEvent event;
2711 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002712 event = mCryptConnector.execute("cryptfs", "clearpw");
Paul Lawrence945490c2014-03-27 16:37:28 +00002713 } catch (NativeDaemonConnectorException e) {
2714 throw e.rethrowAsParcelableException();
2715 }
2716 }
2717
2718 @Override
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002719 public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002720 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002721 waitForReady();
2722
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002723 try {
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002724 mCryptConnector.execute("cryptfs", "create_user_key", userId, serialNumber,
2725 ephemeral ? 1 : 0);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002726 } catch (NativeDaemonConnectorException e) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002727 throw e.rethrowAsParcelableException();
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002728 }
2729 }
2730
Paul Crowley7ec733f2015-05-19 12:42:00 +01002731 @Override
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002732 public void destroyUserKey(int userId) {
2733 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowley7ec733f2015-05-19 12:42:00 +01002734 waitForReady();
2735
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002736 try {
2737 mCryptConnector.execute("cryptfs", "destroy_user_key", userId);
2738 } catch (NativeDaemonConnectorException e) {
2739 throw e.rethrowAsParcelableException();
2740 }
2741 }
2742
2743 @Override
2744 public void unlockUserKey(int userId, int serialNumber, byte[] token) {
2745 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2746 waitForReady();
2747
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07002748 // When a user has secure lock screen, require a challenge token to
2749 // actually unlock. This check is mostly in place for emulation mode.
2750 if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(token)) {
2751 throw new IllegalStateException("Token required to unlock secure user " + userId);
2752 }
2753
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002754 final String encodedToken;
2755 if (ArrayUtils.isEmpty(token)) {
2756 encodedToken = "!";
2757 } else {
2758 encodedToken = HexDump.toHexString(token);
Paul Crowley7ec733f2015-05-19 12:42:00 +01002759 }
2760
2761 try {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002762 mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber,
2763 new SensitiveArg(encodedToken));
Paul Crowley7ec733f2015-05-19 12:42:00 +01002764 } catch (NativeDaemonConnectorException e) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002765 throw e.rethrowAsParcelableException();
2766 }
2767
2768 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002769 mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002770 }
2771 }
2772
2773 @Override
2774 public void lockUserKey(int userId) {
2775 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2776 waitForReady();
2777
2778 try {
2779 mCryptConnector.execute("cryptfs", "lock_user_key", userId);
2780 } catch (NativeDaemonConnectorException e) {
2781 throw e.rethrowAsParcelableException();
2782 }
2783
2784 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002785 mLocalUnlockedUsers = ArrayUtils.removeInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002786 }
2787 }
2788
2789 @Override
2790 public boolean isUserKeyUnlocked(int userId) {
Jeff Sharkeyba512352015-11-12 20:17:45 -08002791 if (StorageManager.isFileBasedEncryptionEnabled()) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002792 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002793 return ArrayUtils.contains(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002794 }
2795 } else {
2796 return true;
2797 }
2798 }
2799
2800 @Override
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002801 public void prepareUserStorage(
2802 String volumeUuid, int userId, int serialNumber, boolean ephemeral) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002803 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2804 waitForReady();
2805
2806 try {
2807 mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid),
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002808 userId, serialNumber, ephemeral ? 1 : 0);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002809 } catch (NativeDaemonConnectorException e) {
2810 throw e.rethrowAsParcelableException();
Paul Crowley7ec733f2015-05-19 12:42:00 +01002811 }
2812 }
2813
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002814 @Override
Daichi Hirono9e8d9e22015-11-13 14:37:00 +09002815 public ParcelFileDescriptor mountAppFuse(String name) throws RemoteException {
Daichi Hironobee50c02015-12-14 11:00:54 +09002816 try {
2817 final NativeDaemonEvent event =
2818 mConnector.execute("appfuse", "mount", Binder.getCallingUid(), name);
2819 if (event.getFileDescriptors() == null) {
2820 Log.e(TAG, "AppFuse FD from vold is null.");
2821 return null;
2822 }
2823 return new ParcelFileDescriptor(event.getFileDescriptors()[0]);
2824 } catch (NativeDaemonConnectorException e) {
2825 throw e.rethrowAsParcelableException();
2826 }
Daichi Hirono9e8d9e22015-11-13 14:37:00 +09002827 }
2828
2829 @Override
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002830 public int mkdirs(String callingPkg, String appPath) {
2831 final int userId = UserHandle.getUserId(Binder.getCallingUid());
2832 final UserEnvironment userEnv = new UserEnvironment(userId);
2833
2834 // Validate that reported package name belongs to caller
2835 final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
2836 Context.APP_OPS_SERVICE);
2837 appOps.checkPackage(Binder.getCallingUid(), callingPkg);
2838
Jeff Sharkey48877892015-03-18 11:27:19 -07002839 File appFile = null;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002840 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07002841 appFile = new File(appPath).getCanonicalFile();
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002842 } catch (IOException e) {
2843 Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
2844 return -1;
2845 }
2846
2847 // Try translating the app path into a vold path, but require that it
2848 // belong to the calling package.
Jeff Sharkey48877892015-03-18 11:27:19 -07002849 if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) ||
2850 FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) ||
2851 FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) {
2852 appPath = appFile.getAbsolutePath();
2853 if (!appPath.endsWith("/")) {
2854 appPath = appPath + "/";
2855 }
2856
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002857 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07002858 mConnector.execute("volume", "mkdirs", appPath);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002859 return 0;
2860 } catch (NativeDaemonConnectorException e) {
2861 return e.getCode();
2862 }
2863 }
2864
Jeff Sharkey48877892015-03-18 11:27:19 -07002865 throw new SecurityException("Invalid mkdirs path: " + appFile);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002866 }
2867
2868 @Override
Jeff Sharkey46349872015-07-28 10:49:47 -07002869 public StorageVolume[] getVolumeList(int uid, String packageName, int flags) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002870 final int userId = UserHandle.getUserId(uid);
Jeff Sharkey46349872015-07-28 10:49:47 -07002871 final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0;
2872
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002873 boolean reportUnmounted = false;
Jeff Sharkey48877892015-03-18 11:27:19 -07002874 boolean foundPrimary = false;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002875
Svetoslav38c3dbb2015-07-14 11:27:06 -07002876 final long identity = Binder.clearCallingIdentity();
2877 try {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002878 if (!mMountServiceInternal.hasExternalStorage(uid, packageName)) {
2879 reportUnmounted = true;
2880 }
2881 if (!isUserKeyUnlocked(userId)) {
2882 reportUnmounted = true;
2883 }
Svetoslav38c3dbb2015-07-14 11:27:06 -07002884 } finally {
2885 Binder.restoreCallingIdentity(identity);
2886 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07002887
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002888 final ArrayList<StorageVolume> res = new ArrayList<>();
Jeff Sharkey48877892015-03-18 11:27:19 -07002889 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002890 for (int i = 0; i < mVolumes.size(); i++) {
2891 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey46349872015-07-28 10:49:47 -07002892 if (forWrite ? vol.isVisibleForWrite(userId) : vol.isVisibleForRead(userId)) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07002893 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
2894 reportUnmounted);
Jeff Sharkey48877892015-03-18 11:27:19 -07002895 if (vol.isPrimary()) {
2896 res.add(0, userVol);
2897 foundPrimary = true;
2898 } else {
2899 res.add(userVol);
2900 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002901 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002902 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002903 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002904
2905 if (!foundPrimary) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002906 Log.w(TAG, "No primary storage defined yet; hacking together a stub");
Jeff Sharkey48877892015-03-18 11:27:19 -07002907
2908 final boolean primaryPhysical = SystemProperties.getBoolean(
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002909 StorageManager.PROP_PRIMARY_PHYSICAL, false);
Jeff Sharkey48877892015-03-18 11:27:19 -07002910
2911 final String id = "stub_primary";
2912 final File path = Environment.getLegacyExternalStorageDirectory();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002913 final String description = mContext.getString(android.R.string.unknownName);
Jeff Sharkey48877892015-03-18 11:27:19 -07002914 final boolean primary = true;
2915 final boolean removable = primaryPhysical;
2916 final boolean emulated = !primaryPhysical;
2917 final long mtpReserveSize = 0L;
2918 final boolean allowMassStorage = false;
2919 final long maxFileSize = 0L;
2920 final UserHandle owner = new UserHandle(userId);
2921 final String uuid = null;
Jeff Sharkey48877892015-03-18 11:27:19 -07002922 final String state = Environment.MEDIA_REMOVED;
2923
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07002924 res.add(0, new StorageVolume(id, StorageVolume.STORAGE_ID_INVALID, path,
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002925 description, primary, removable, emulated, mtpReserveSize,
2926 allowMassStorage, maxFileSize, owner, uuid, state));
Jeff Sharkey48877892015-03-18 11:27:19 -07002927 }
2928
2929 return res.toArray(new StorageVolume[res.size()]);
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002930 }
2931
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002932 @Override
2933 public DiskInfo[] getDisks() {
2934 synchronized (mLock) {
2935 final DiskInfo[] res = new DiskInfo[mDisks.size()];
2936 for (int i = 0; i < mDisks.size(); i++) {
2937 res[i] = mDisks.valueAt(i);
2938 }
2939 return res;
2940 }
2941 }
2942
2943 @Override
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07002944 public VolumeInfo[] getVolumes(int flags) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002945 synchronized (mLock) {
2946 final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
2947 for (int i = 0; i < mVolumes.size(); i++) {
2948 res[i] = mVolumes.valueAt(i);
2949 }
2950 return res;
2951 }
2952 }
2953
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07002954 @Override
2955 public VolumeRecord[] getVolumeRecords(int flags) {
2956 synchronized (mLock) {
2957 final VolumeRecord[] res = new VolumeRecord[mRecords.size()];
2958 for (int i = 0; i < mRecords.size(); i++) {
2959 res[i] = mRecords.valueAt(i);
2960 }
2961 return res;
2962 }
2963 }
2964
Kenny Rootaf9d6672010-10-08 09:21:39 -07002965 private void addObbStateLocked(ObbState obbState) throws RemoteException {
2966 final IBinder binder = obbState.getBinder();
2967 List<ObbState> obbStates = mObbMounts.get(binder);
Kenny Root5919ac62010-10-05 09:49:40 -07002968
Kenny Rootaf9d6672010-10-08 09:21:39 -07002969 if (obbStates == null) {
2970 obbStates = new ArrayList<ObbState>();
2971 mObbMounts.put(binder, obbStates);
2972 } else {
2973 for (final ObbState o : obbStates) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002974 if (o.rawPath.equals(obbState.rawPath)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07002975 throw new IllegalStateException("Attempt to add ObbState twice. "
2976 + "This indicates an error in the MountService logic.");
Kenny Root5919ac62010-10-05 09:49:40 -07002977 }
2978 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002979 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07002980
2981 obbStates.add(obbState);
2982 try {
2983 obbState.link();
2984 } catch (RemoteException e) {
2985 /*
2986 * The binder died before we could link it, so clean up our state
2987 * and return failure.
2988 */
2989 obbStates.remove(obbState);
2990 if (obbStates.isEmpty()) {
2991 mObbMounts.remove(binder);
2992 }
2993
2994 // Rethrow the error so mountObb can get it
2995 throw e;
2996 }
2997
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002998 mObbPathToStateMap.put(obbState.rawPath, obbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07002999 }
3000
Kenny Rootaf9d6672010-10-08 09:21:39 -07003001 private void removeObbStateLocked(ObbState obbState) {
3002 final IBinder binder = obbState.getBinder();
3003 final List<ObbState> obbStates = mObbMounts.get(binder);
3004 if (obbStates != null) {
3005 if (obbStates.remove(obbState)) {
3006 obbState.unlink();
Kenny Root05105f72010-09-22 17:29:43 -07003007 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003008 if (obbStates.isEmpty()) {
3009 mObbMounts.remove(binder);
3010 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003011 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003012
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003013 mObbPathToStateMap.remove(obbState.rawPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003014 }
3015
Kenny Roota02b8b02010-08-05 16:14:17 -07003016 private class ObbActionHandler extends Handler {
3017 private boolean mBound = false;
Kenny Root480afe72010-10-07 10:17:50 -07003018 private final List<ObbAction> mActions = new LinkedList<ObbAction>();
Kenny Roota02b8b02010-08-05 16:14:17 -07003019
3020 ObbActionHandler(Looper l) {
3021 super(l);
3022 }
3023
3024 @Override
3025 public void handleMessage(Message msg) {
3026 switch (msg.what) {
3027 case OBB_RUN_ACTION: {
Kenny Root480afe72010-10-07 10:17:50 -07003028 final ObbAction action = (ObbAction) msg.obj;
Kenny Roota02b8b02010-08-05 16:14:17 -07003029
3030 if (DEBUG_OBB)
3031 Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
3032
3033 // If a bind was already initiated we don't really
3034 // need to do anything. The pending install
3035 // will be processed later on.
3036 if (!mBound) {
3037 // If this is the only one pending we might
3038 // have to bind to the service again.
3039 if (!connectToService()) {
3040 Slog.e(TAG, "Failed to bind to media container service");
3041 action.handleError();
3042 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003043 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003044 }
Kenny Root735de3b2010-09-30 14:11:39 -07003045
Kenny Root735de3b2010-09-30 14:11:39 -07003046 mActions.add(action);
Kenny Roota02b8b02010-08-05 16:14:17 -07003047 break;
3048 }
3049 case OBB_MCS_BOUND: {
3050 if (DEBUG_OBB)
3051 Slog.i(TAG, "OBB_MCS_BOUND");
3052 if (msg.obj != null) {
3053 mContainerService = (IMediaContainerService) msg.obj;
3054 }
3055 if (mContainerService == null) {
3056 // Something seriously wrong. Bail out
3057 Slog.e(TAG, "Cannot bind to media container service");
3058 for (ObbAction action : mActions) {
3059 // Indicate service bind error
3060 action.handleError();
3061 }
3062 mActions.clear();
3063 } else if (mActions.size() > 0) {
Kenny Root480afe72010-10-07 10:17:50 -07003064 final ObbAction action = mActions.get(0);
Kenny Roota02b8b02010-08-05 16:14:17 -07003065 if (action != null) {
3066 action.execute(this);
3067 }
3068 } else {
3069 // Should never happen ideally.
3070 Slog.w(TAG, "Empty queue");
3071 }
3072 break;
3073 }
3074 case OBB_MCS_RECONNECT: {
3075 if (DEBUG_OBB)
3076 Slog.i(TAG, "OBB_MCS_RECONNECT");
3077 if (mActions.size() > 0) {
3078 if (mBound) {
3079 disconnectService();
3080 }
3081 if (!connectToService()) {
3082 Slog.e(TAG, "Failed to bind to media container service");
3083 for (ObbAction action : mActions) {
3084 // Indicate service bind error
3085 action.handleError();
3086 }
3087 mActions.clear();
3088 }
3089 }
3090 break;
3091 }
3092 case OBB_MCS_UNBIND: {
3093 if (DEBUG_OBB)
3094 Slog.i(TAG, "OBB_MCS_UNBIND");
3095
3096 // Delete pending install
3097 if (mActions.size() > 0) {
3098 mActions.remove(0);
3099 }
3100 if (mActions.size() == 0) {
3101 if (mBound) {
3102 disconnectService();
3103 }
3104 } else {
3105 // There are more pending requests in queue.
3106 // Just post MCS_BOUND message to trigger processing
3107 // of next pending install.
3108 mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
3109 }
3110 break;
3111 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003112 case OBB_FLUSH_MOUNT_STATE: {
3113 final String path = (String) msg.obj;
3114
3115 if (DEBUG_OBB)
3116 Slog.i(TAG, "Flushing all OBB state for path " + path);
3117
3118 synchronized (mObbMounts) {
3119 final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
3120
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003121 final Iterator<ObbState> i = mObbPathToStateMap.values().iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003122 while (i.hasNext()) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003123 final ObbState state = i.next();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003124
3125 /*
3126 * If this entry's source file is in the volume path
3127 * that got unmounted, remove it because it's no
3128 * longer valid.
3129 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003130 if (state.canonicalPath.startsWith(path)) {
3131 obbStatesToRemove.add(state);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003132 }
3133 }
3134
3135 for (final ObbState obbState : obbStatesToRemove) {
3136 if (DEBUG_OBB)
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003137 Slog.i(TAG, "Removing state for " + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003138
3139 removeObbStateLocked(obbState);
3140
3141 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003142 obbState.token.onObbResult(obbState.rawPath, obbState.nonce,
Kenny Rootaf9d6672010-10-08 09:21:39 -07003143 OnObbStateChangeListener.UNMOUNTED);
3144 } catch (RemoteException e) {
3145 Slog.i(TAG, "Couldn't send unmount notification for OBB: "
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003146 + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003147 }
3148 }
3149 }
3150 break;
3151 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003152 }
3153 }
3154
3155 private boolean connectToService() {
3156 if (DEBUG_OBB)
3157 Slog.i(TAG, "Trying to bind to DefaultContainerService");
3158
3159 Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Jeff Sharkey6dce4962015-07-03 18:08:41 -07003160 if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE,
Xiaohui Chene4de5a02015-09-22 15:33:31 -07003161 UserHandle.SYSTEM)) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003162 mBound = true;
3163 return true;
3164 }
3165 return false;
3166 }
3167
3168 private void disconnectService() {
3169 mContainerService = null;
3170 mBound = false;
3171 mContext.unbindService(mDefContainerConn);
3172 }
3173 }
3174
3175 abstract class ObbAction {
3176 private static final int MAX_RETRIES = 3;
3177 private int mRetries;
3178
3179 ObbState mObbState;
3180
3181 ObbAction(ObbState obbState) {
3182 mObbState = obbState;
3183 }
3184
3185 public void execute(ObbActionHandler handler) {
3186 try {
3187 if (DEBUG_OBB)
Ben Komalo444eca22011-09-01 15:17:44 -07003188 Slog.i(TAG, "Starting to execute action: " + toString());
Kenny Roota02b8b02010-08-05 16:14:17 -07003189 mRetries++;
3190 if (mRetries > MAX_RETRIES) {
3191 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
Kenny Root480afe72010-10-07 10:17:50 -07003192 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003193 handleError();
Kenny Roota02b8b02010-08-05 16:14:17 -07003194 } else {
3195 handleExecute();
3196 if (DEBUG_OBB)
3197 Slog.i(TAG, "Posting install MCS_UNBIND");
3198 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
3199 }
3200 } catch (RemoteException e) {
3201 if (DEBUG_OBB)
3202 Slog.i(TAG, "Posting install MCS_RECONNECT");
3203 mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
3204 } catch (Exception e) {
3205 if (DEBUG_OBB)
3206 Slog.d(TAG, "Error handling OBB action", e);
3207 handleError();
Kenny Root17eb6fb2010-10-06 15:02:52 -07003208 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003209 }
3210 }
3211
Kenny Root05105f72010-09-22 17:29:43 -07003212 abstract void handleExecute() throws RemoteException, IOException;
Kenny Roota02b8b02010-08-05 16:14:17 -07003213 abstract void handleError();
Kenny Root38cf8862010-09-26 14:18:51 -07003214
3215 protected ObbInfo getObbInfo() throws IOException {
3216 ObbInfo obbInfo;
3217 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003218 obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003219 } catch (RemoteException e) {
3220 Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003221 + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003222 obbInfo = null;
3223 }
3224 if (obbInfo == null) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003225 throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003226 }
3227 return obbInfo;
3228 }
3229
Kenny Rootaf9d6672010-10-08 09:21:39 -07003230 protected void sendNewStatusOrIgnore(int status) {
3231 if (mObbState == null || mObbState.token == null) {
3232 return;
3233 }
3234
Kenny Root38cf8862010-09-26 14:18:51 -07003235 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003236 mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
Kenny Root38cf8862010-09-26 14:18:51 -07003237 } catch (RemoteException e) {
3238 Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
3239 }
3240 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003241 }
3242
3243 class MountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003244 private final String mKey;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003245 private final int mCallingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003246
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003247 MountObbAction(ObbState obbState, String key, int callingUid) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003248 super(obbState);
3249 mKey = key;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003250 mCallingUid = callingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003251 }
3252
Jason parks5af0b912010-11-29 09:05:25 -06003253 @Override
Kenny Root735de3b2010-09-30 14:11:39 -07003254 public void handleExecute() throws IOException, RemoteException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003255 waitForReady();
3256 warnOnNotMounted();
3257
Kenny Root38cf8862010-09-26 14:18:51 -07003258 final ObbInfo obbInfo = getObbInfo();
3259
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003260 if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003261 Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
3262 + " which is owned by " + obbInfo.packageName);
3263 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3264 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003265 }
3266
Kenny Rootaf9d6672010-10-08 09:21:39 -07003267 final boolean isMounted;
3268 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003269 isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003270 }
3271 if (isMounted) {
3272 Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
3273 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
3274 return;
3275 }
3276
Kenny Rootaf9d6672010-10-08 09:21:39 -07003277 final String hashedKey;
3278 if (mKey == null) {
3279 hashedKey = "none";
3280 } else {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003281 try {
Kenny Root3b1abba2010-10-13 15:00:07 -07003282 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
3283
3284 KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
3285 PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
3286 SecretKey key = factory.generateSecret(ks);
3287 BigInteger bi = new BigInteger(key.getEncoded());
3288 hashedKey = bi.toString(16);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003289 } catch (NoSuchAlgorithmException e) {
Kenny Root3b1abba2010-10-13 15:00:07 -07003290 Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
3291 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
3292 return;
3293 } catch (InvalidKeySpecException e) {
3294 Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
3295 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root38cf8862010-09-26 14:18:51 -07003296 return;
3297 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003298 }
Kenny Root38cf8862010-09-26 14:18:51 -07003299
Kenny Rootaf9d6672010-10-08 09:21:39 -07003300 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003301 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003302 mConnector.execute("obb", "mount", mObbState.canonicalPath, new SensitiveArg(hashedKey),
Jeff Sharkey56cd6462013-06-07 15:09:15 -07003303 mObbState.ownerGid);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003304 } catch (NativeDaemonConnectorException e) {
3305 int code = e.getCode();
3306 if (code != VoldResponseCode.OpFailedStorageBusy) {
3307 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003308 }
3309 }
3310
Kenny Rootaf9d6672010-10-08 09:21:39 -07003311 if (rc == StorageResultCode.OperationSucceeded) {
3312 if (DEBUG_OBB)
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003313 Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003314
3315 synchronized (mObbMounts) {
3316 addObbStateLocked(mObbState);
3317 }
3318
3319 sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
Kenny Root02c87302010-07-01 08:10:18 -07003320 } else {
Kenny Root05105f72010-09-22 17:29:43 -07003321 Slog.e(TAG, "Couldn't mount OBB file: " + rc);
Kenny Roota02b8b02010-08-05 16:14:17 -07003322
Kenny Rootaf9d6672010-10-08 09:21:39 -07003323 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
Kenny Root02c87302010-07-01 08:10:18 -07003324 }
3325 }
3326
Jason parks5af0b912010-11-29 09:05:25 -06003327 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003328 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003329 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root02c87302010-07-01 08:10:18 -07003330 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003331
3332 @Override
3333 public String toString() {
3334 StringBuilder sb = new StringBuilder();
3335 sb.append("MountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003336 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003337 sb.append('}');
3338 return sb.toString();
3339 }
3340 }
3341
3342 class UnmountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003343 private final boolean mForceUnmount;
Kenny Roota02b8b02010-08-05 16:14:17 -07003344
3345 UnmountObbAction(ObbState obbState, boolean force) {
3346 super(obbState);
3347 mForceUnmount = force;
3348 }
3349
Jason parks5af0b912010-11-29 09:05:25 -06003350 @Override
Kenny Root38cf8862010-09-26 14:18:51 -07003351 public void handleExecute() throws IOException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003352 waitForReady();
3353 warnOnNotMounted();
3354
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003355 final ObbState existingState;
Kenny Root38cf8862010-09-26 14:18:51 -07003356 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003357 existingState = mObbPathToStateMap.get(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003358 }
Kenny Root38cf8862010-09-26 14:18:51 -07003359
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003360 if (existingState == null) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003361 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
3362 return;
3363 }
3364
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003365 if (existingState.ownerGid != mObbState.ownerGid) {
3366 Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
3367 + " (owned by GID " + existingState.ownerGid + ")");
Kenny Rootaf9d6672010-10-08 09:21:39 -07003368 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3369 return;
3370 }
3371
Kenny Rootaf9d6672010-10-08 09:21:39 -07003372 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003373 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003374 final Command cmd = new Command("obb", "unmount", mObbState.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08003375 if (mForceUnmount) {
3376 cmd.appendArg("force");
3377 }
3378 mConnector.execute(cmd);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003379 } catch (NativeDaemonConnectorException e) {
3380 int code = e.getCode();
3381 if (code == VoldResponseCode.OpFailedStorageBusy) {
3382 rc = StorageResultCode.OperationFailedStorageBusy;
3383 } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
3384 // If it's not mounted then we've already won.
3385 rc = StorageResultCode.OperationSucceeded;
3386 } else {
3387 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003388 }
3389 }
3390
Kenny Rootaf9d6672010-10-08 09:21:39 -07003391 if (rc == StorageResultCode.OperationSucceeded) {
3392 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003393 removeObbStateLocked(existingState);
Kenny Root38cf8862010-09-26 14:18:51 -07003394 }
3395
Kenny Rootaf9d6672010-10-08 09:21:39 -07003396 sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
Kenny Roota02b8b02010-08-05 16:14:17 -07003397 } else {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003398 Slog.w(TAG, "Could not unmount OBB: " + existingState);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003399 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
Kenny Roota02b8b02010-08-05 16:14:17 -07003400 }
3401 }
3402
Jason parks5af0b912010-11-29 09:05:25 -06003403 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003404 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003405 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Roota02b8b02010-08-05 16:14:17 -07003406 }
3407
3408 @Override
3409 public String toString() {
3410 StringBuilder sb = new StringBuilder();
3411 sb.append("UnmountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003412 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003413 sb.append(",force=");
3414 sb.append(mForceUnmount);
Kenny Roota02b8b02010-08-05 16:14:17 -07003415 sb.append('}');
3416 return sb.toString();
3417 }
Kenny Root02c87302010-07-01 08:10:18 -07003418 }
Kenny Root38cf8862010-09-26 14:18:51 -07003419
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003420 private static class Callbacks extends Handler {
3421 private static final int MSG_STORAGE_STATE_CHANGED = 1;
3422 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003423 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
3424 private static final int MSG_VOLUME_FORGOTTEN = 4;
3425 private static final int MSG_DISK_SCANNED = 5;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003426 private static final int MSG_DISK_DESTROYED = 6;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003427
3428 private final RemoteCallbackList<IMountServiceListener>
3429 mCallbacks = new RemoteCallbackList<>();
3430
3431 public Callbacks(Looper looper) {
3432 super(looper);
3433 }
3434
3435 public void register(IMountServiceListener callback) {
3436 mCallbacks.register(callback);
3437 }
3438
3439 public void unregister(IMountServiceListener callback) {
3440 mCallbacks.unregister(callback);
3441 }
3442
3443 @Override
3444 public void handleMessage(Message msg) {
3445 final SomeArgs args = (SomeArgs) msg.obj;
3446 final int n = mCallbacks.beginBroadcast();
3447 for (int i = 0; i < n; i++) {
3448 final IMountServiceListener callback = mCallbacks.getBroadcastItem(i);
3449 try {
3450 invokeCallback(callback, msg.what, args);
3451 } catch (RemoteException ignored) {
3452 }
3453 }
3454 mCallbacks.finishBroadcast();
3455 args.recycle();
3456 }
3457
3458 private void invokeCallback(IMountServiceListener callback, int what, SomeArgs args)
3459 throws RemoteException {
3460 switch (what) {
3461 case MSG_STORAGE_STATE_CHANGED: {
3462 callback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
3463 (String) args.arg3);
3464 break;
3465 }
3466 case MSG_VOLUME_STATE_CHANGED: {
3467 callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
3468 break;
3469 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07003470 case MSG_VOLUME_RECORD_CHANGED: {
3471 callback.onVolumeRecordChanged((VolumeRecord) args.arg1);
3472 break;
3473 }
3474 case MSG_VOLUME_FORGOTTEN: {
3475 callback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003476 break;
3477 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003478 case MSG_DISK_SCANNED: {
3479 callback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003480 break;
3481 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003482 case MSG_DISK_DESTROYED: {
3483 callback.onDiskDestroyed((DiskInfo) args.arg1);
3484 break;
3485 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003486 }
3487 }
3488
3489 private void notifyStorageStateChanged(String path, String oldState, String newState) {
3490 final SomeArgs args = SomeArgs.obtain();
3491 args.arg1 = path;
3492 args.arg2 = oldState;
3493 args.arg3 = newState;
3494 obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
3495 }
3496
3497 private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
3498 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003499 args.arg1 = vol.clone();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003500 args.argi2 = oldState;
3501 args.argi3 = newState;
3502 obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
3503 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003504
Jeff Sharkey50a05452015-04-29 11:24:52 -07003505 private void notifyVolumeRecordChanged(VolumeRecord rec) {
3506 final SomeArgs args = SomeArgs.obtain();
3507 args.arg1 = rec.clone();
3508 obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
3509 }
3510
3511 private void notifyVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003512 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003513 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003514 obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003515 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003516
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003517 private void notifyDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003518 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003519 args.arg1 = disk.clone();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003520 args.argi2 = volumeCount;
3521 obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003522 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003523
3524 private void notifyDiskDestroyed(DiskInfo disk) {
3525 final SomeArgs args = SomeArgs.obtain();
3526 args.arg1 = disk.clone();
3527 obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
3528 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003529 }
3530
Kenny Root38cf8862010-09-26 14:18:51 -07003531 @Override
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003532 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
3533 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
3534
3535 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003536 synchronized (mLock) {
3537 pw.println("Disks:");
3538 pw.increaseIndent();
3539 for (int i = 0; i < mDisks.size(); i++) {
3540 final DiskInfo disk = mDisks.valueAt(i);
3541 disk.dump(pw);
3542 }
3543 pw.decreaseIndent();
3544
3545 pw.println();
3546 pw.println("Volumes:");
3547 pw.increaseIndent();
3548 for (int i = 0; i < mVolumes.size(); i++) {
3549 final VolumeInfo vol = mVolumes.valueAt(i);
3550 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue;
3551 vol.dump(pw);
3552 }
3553 pw.decreaseIndent();
3554
3555 pw.println();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003556 pw.println("Records:");
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003557 pw.increaseIndent();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003558 for (int i = 0; i < mRecords.size(); i++) {
3559 final VolumeRecord note = mRecords.valueAt(i);
3560 note.dump(pw);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003561 }
3562 pw.decreaseIndent();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07003563
3564 pw.println();
3565 pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07003566 pw.println("Force adoptable: " + mForceAdoptable);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08003567 pw.println();
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003568 pw.println("Local unlocked users: " + Arrays.toString(mLocalUnlockedUsers));
3569 pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003570 }
Kenny Root38cf8862010-09-26 14:18:51 -07003571
Kenny Root38cf8862010-09-26 14:18:51 -07003572 synchronized (mObbMounts) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003573 pw.println();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003574 pw.println("mObbMounts:");
3575 pw.increaseIndent();
3576 final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet()
3577 .iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003578 while (binders.hasNext()) {
3579 Entry<IBinder, List<ObbState>> e = binders.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003580 pw.println(e.getKey() + ":");
3581 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003582 final List<ObbState> obbStates = e.getValue();
Kenny Root38cf8862010-09-26 14:18:51 -07003583 for (final ObbState obbState : obbStates) {
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003584 pw.println(obbState);
Kenny Root38cf8862010-09-26 14:18:51 -07003585 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003586 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003587 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003588 pw.decreaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003589
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003590 pw.println();
3591 pw.println("mObbPathToStateMap:");
3592 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003593 final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
3594 while (maps.hasNext()) {
3595 final Entry<String, ObbState> e = maps.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003596 pw.print(e.getKey());
3597 pw.print(" -> ");
3598 pw.println(e.getValue());
Kenny Rootaf9d6672010-10-08 09:21:39 -07003599 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003600 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003601 }
Kenny Root4161f9b2011-07-13 09:48:33 -07003602
Robert Greenwalt470fd722012-01-18 12:51:15 -08003603 pw.println();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003604 pw.println("mConnection:");
3605 pw.increaseIndent();
Robert Greenwalt470fd722012-01-18 12:51:15 -08003606 mConnector.dump(fd, pw, args);
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003607 pw.decreaseIndent();
Christopher Tate7265abe2014-11-21 13:54:45 -08003608
Christopher Tate7265abe2014-11-21 13:54:45 -08003609 pw.println();
3610 pw.print("Last maintenance: ");
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07003611 pw.println(TimeUtils.formatForLogging(mLastMaintenance));
Kenny Root38cf8862010-09-26 14:18:51 -07003612 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003613
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003614 /** {@inheritDoc} */
Jeff Sharkey48877892015-03-18 11:27:19 -07003615 @Override
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003616 public void monitor() {
3617 if (mConnector != null) {
3618 mConnector.monitor();
3619 }
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07003620 if (mCryptConnector != null) {
3621 mCryptConnector.monitor();
3622 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003623 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003624
3625 private final class MountServiceInternalImpl extends MountServiceInternal {
3626 // Not guarded by a lock.
3627 private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
3628 new CopyOnWriteArrayList<>();
3629
3630 @Override
3631 public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
3632 // No locking - CopyOnWriteArrayList
3633 mPolicies.add(policy);
3634 }
3635
3636 @Override
3637 public void onExternalStoragePolicyChanged(int uid, String packageName) {
3638 final int mountMode = getExternalStorageMountMode(uid, packageName);
3639 remountUidExternalStorage(uid, mountMode);
3640 }
3641
3642 @Override
3643 public int getExternalStorageMountMode(int uid, String packageName) {
3644 // No locking - CopyOnWriteArrayList
3645 int mountMode = Integer.MAX_VALUE;
3646 for (ExternalStorageMountPolicy policy : mPolicies) {
3647 final int policyMode = policy.getMountMode(uid, packageName);
3648 if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
3649 return Zygote.MOUNT_EXTERNAL_NONE;
3650 }
3651 mountMode = Math.min(mountMode, policyMode);
3652 }
3653 if (mountMode == Integer.MAX_VALUE) {
3654 return Zygote.MOUNT_EXTERNAL_NONE;
3655 }
3656 return mountMode;
3657 }
3658
3659 public boolean hasExternalStorage(int uid, String packageName) {
Amith Yamasani2bd5cff2015-07-22 14:42:31 -07003660 // No need to check for system uid. This avoids a deadlock between
3661 // PackageManagerService and AppOpsService.
3662 if (uid == Process.SYSTEM_UID) {
3663 return true;
3664 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003665 // No locking - CopyOnWriteArrayList
3666 for (ExternalStorageMountPolicy policy : mPolicies) {
3667 final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
3668 if (!policyHasStorage) {
3669 return false;
3670 }
3671 }
3672 return true;
3673 }
3674 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003675}