blob: 4cc293125bcc53d29820a886ed4e2bd103b39425 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Jeff Sharkey4c099d02015-05-15 13:45:00 -070019import static com.android.internal.util.XmlUtils.readBooleanAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070020import static com.android.internal.util.XmlUtils.readIntAttribute;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070021import static com.android.internal.util.XmlUtils.readLongAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070022import static com.android.internal.util.XmlUtils.readStringAttribute;
Jeff Sharkey4c099d02015-05-15 13:45:00 -070023import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070024import static com.android.internal.util.XmlUtils.writeIntAttribute;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070025import static com.android.internal.util.XmlUtils.writeLongAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070026import static com.android.internal.util.XmlUtils.writeStringAttribute;
Jeff Sharkey5217cac2015-12-20 15:34:01 -070027
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070028import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
29import static org.xmlpull.v1.XmlPullParser.START_TAG;
30
Jason parks8888c592011-01-20 22:46:41 -060031import android.Manifest;
Jeff Sharkeyef10ee02015-07-05 14:17:27 -070032import android.annotation.Nullable;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -070033import android.app.ActivityManager;
Elliott Hughesf839b4f2014-09-26 12:30:47 -070034import android.app.ActivityManagerNative;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -070035import android.app.AppOpsManager;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070036import android.app.IActivityManager;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070037import android.content.BroadcastReceiver;
Kenny Roota02b8b02010-08-05 16:14:17 -070038import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.content.Context;
40import android.content.Intent;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070041import android.content.IntentFilter;
Kenny Roota02b8b02010-08-05 16:14:17 -070042import android.content.ServiceConnection;
Jeff Sharkey275e3e42015-04-24 16:10:32 -070043import android.content.pm.IPackageMoveObserver;
44import android.content.pm.PackageManager;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070045import android.content.pm.ProviderInfo;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070046import android.content.pm.UserInfo;
Elliott Hughesf839b4f2014-09-26 12:30:47 -070047import android.content.res.Configuration;
Kenny Root02c87302010-07-01 08:10:18 -070048import android.content.res.ObbInfo;
Felipe Lemec0d3f0e2016-10-10 17:12:20 -070049import android.net.TrafficStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.net.Uri;
Kenny Root02c87302010-07-01 08:10:18 -070051import android.os.Binder;
Jeff Sharkey4c099d02015-05-15 13:45:00 -070052import android.os.DropBoxManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070053import android.os.Environment;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070054import android.os.Environment.UserEnvironment;
Jeff Sharkey48877892015-03-18 11:27:19 -070055import android.os.FileUtils;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080056import android.os.Handler;
Dianne Hackbornefa92b22013-05-03 14:11:43 -070057import android.os.HandlerThread;
Kenny Roota02b8b02010-08-05 16:14:17 -070058import android.os.IBinder;
Daniel Sandler5f27ef42010-03-16 15:42:02 -040059import android.os.Looper;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080060import android.os.Message;
Daichi Hirono9e8d9e22015-11-13 14:37:00 +090061import android.os.ParcelFileDescriptor;
Jeff Sharkeyce14cd02015-12-07 15:35:42 -070062import android.os.PowerManager;
Jeff Sharkey9527b222015-06-24 15:24:48 -070063import android.os.Process;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070064import android.os.RemoteCallbackList;
San Mehat4270e1e2010-01-29 05:32:19 -080065import android.os.RemoteException;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -080066import android.os.ServiceManager;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -070067import android.os.SystemClock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070069import android.os.UserHandle;
Emily Bernier92aa5a22014-07-07 10:11:48 -040070import android.os.UserManager;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070071import android.os.storage.DiskInfo;
Kenny Roota02b8b02010-08-05 16:14:17 -070072import android.os.storage.IMountService;
73import android.os.storage.IMountServiceListener;
74import android.os.storage.IMountShutdownObserver;
75import android.os.storage.IObbActionListener;
Svet Ganov6ee871e2015-07-10 14:29:33 -070076import android.os.storage.MountServiceInternal;
Kenny Rootaf9d6672010-10-08 09:21:39 -070077import android.os.storage.OnObbStateChangeListener;
Paul Lawrence46791e72014-04-03 09:10:26 -070078import android.os.storage.StorageManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070079import android.os.storage.StorageResultCode;
Mike Lockwood2f6a3882011-05-09 19:08:06 -070080import android.os.storage.StorageVolume;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070081import android.os.storage.VolumeInfo;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070082import android.os.storage.VolumeRecord;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070083import android.provider.MediaStore;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070084import android.provider.Settings;
Jason parksf7b3cd42011-01-27 09:28:25 -060085import android.text.TextUtils;
Jeff Sharkey1783f142015-04-17 10:52:51 -070086import android.text.format.DateUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -070087import android.util.ArrayMap;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070088import android.util.AtomicFile;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070089import android.util.Log;
Felipe Lemec0d3f0e2016-10-10 17:12:20 -070090import android.util.Pair;
San Mehata5078592010-03-25 09:36:54 -070091import android.util.Slog;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070092import android.util.TimeUtils;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070093import android.util.Xml;
Jeff Sharkey48877892015-03-18 11:27:19 -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 Sharkey5217cac2015-12-20 15:34:01 -0700109import libcore.io.IoUtils;
110import libcore.util.EmptyArray;
111
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700112import org.xmlpull.v1.XmlPullParser;
113import org.xmlpull.v1.XmlPullParserException;
114import org.xmlpull.v1.XmlSerializer;
115
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700116import java.io.File;
Kenny Root38cf8862010-09-26 14:18:51 -0700117import java.io.FileDescriptor;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700118import java.io.FileInputStream;
119import java.io.FileNotFoundException;
Christopher Tate7265abe2014-11-21 13:54:45 -0800120import java.io.FileOutputStream;
Kenny Root05105f72010-09-22 17:29:43 -0700121import java.io.IOException;
Kenny Root38cf8862010-09-26 14:18:51 -0700122import java.io.PrintWriter;
Kenny Root3b1abba2010-10-13 15:00:07 -0700123import java.math.BigInteger;
Paul Lawrence8e397362014-01-27 15:22:30 -0800124import java.nio.charset.StandardCharsets;
Kenny Root735de3b2010-09-30 14:11:39 -0700125import java.security.NoSuchAlgorithmException;
Kenny Root3b1abba2010-10-13 15:00:07 -0700126import java.security.spec.InvalidKeySpecException;
127import java.security.spec.KeySpec;
San Mehat22dd86e2010-01-12 12:21:18 -0800128import java.util.ArrayList;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800129import java.util.Arrays;
Kenny Roota02b8b02010-08-05 16:14:17 -0700130import java.util.HashMap;
San Mehat6cdd9c02010-02-09 14:45:20 -0800131import java.util.HashSet;
Kenny Root38cf8862010-09-26 14:18:51 -0700132import java.util.Iterator;
Kenny Roota02b8b02010-08-05 16:14:17 -0700133import java.util.LinkedList;
134import java.util.List;
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700135import java.util.Locale;
Kenny Roota02b8b02010-08-05 16:14:17 -0700136import java.util.Map;
Kenny Root38cf8862010-09-26 14:18:51 -0700137import java.util.Map.Entry;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700138import java.util.Objects;
Svet Ganov6ee871e2015-07-10 14:29:33 -0700139import java.util.concurrent.CopyOnWriteArrayList;
Kenny Root51a573c2012-05-17 13:30:28 -0700140import java.util.concurrent.CountDownLatch;
141import java.util.concurrent.TimeUnit;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700142import java.util.concurrent.TimeoutException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143
Kenny Root3b1abba2010-10-13 15:00:07 -0700144import javax.crypto.SecretKey;
145import javax.crypto.SecretKeyFactory;
146import javax.crypto.spec.PBEKeySpec;
147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148/**
Jeff Sharkey48877892015-03-18 11:27:19 -0700149 * Service responsible for various storage media. Connects to {@code vold} to
150 * watch for and manage dynamically added storage, such as SD cards and USB mass
151 * storage. Also decides how storage should be presented to users on the device.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 */
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700153class MountService extends IMountService.Stub
154 implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
Jason parks5af0b912010-11-29 09:05:25 -0600155
Christopher Tated417d622013-08-19 16:14:25 -0700156 // Static direct instance pointer for the tightly-coupled idle service to use
157 static MountService sSelf = null;
158
Jeff Sharkey56e62932015-03-21 20:41:00 -0700159 public static class Lifecycle extends SystemService {
160 private MountService mMountService;
161
162 public Lifecycle(Context context) {
163 super(context);
164 }
165
166 @Override
167 public void onStart() {
168 mMountService = new MountService(getContext());
169 publishBinderService("mount", mMountService);
Jeff Sharkeycd575992016-03-29 14:12:49 -0600170 mMountService.start();
Jeff Sharkey56e62932015-03-21 20:41:00 -0700171 }
172
173 @Override
174 public void onBootPhase(int phase) {
175 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
176 mMountService.systemReady();
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900177 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
178 mMountService.bootCompleted();
Jeff Sharkey56e62932015-03-21 20:41:00 -0700179 }
180 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700181
182 @Override
Jeff Sharkeyab15c392016-05-05 11:45:01 -0600183 public void onSwitchUser(int userHandle) {
184 mMountService.mCurrentUserId = userHandle;
185 }
186
187 @Override
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700188 public void onUnlockUser(int userHandle) {
189 mMountService.onUnlockUser(userHandle);
Jeff Sharkey48877892015-03-18 11:27:19 -0700190 }
191
192 @Override
193 public void onCleanupUser(int userHandle) {
194 mMountService.onCleanupUser(userHandle);
195 }
Jeff Sharkey56e62932015-03-21 20:41:00 -0700196 }
197
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800198 private static final boolean DEBUG_EVENTS = false;
Kenny Rootb7db2722011-01-25 16:39:35 -0800199 private static final boolean DEBUG_OBB = false;
Kenny Root02c87302010-07-01 08:10:18 -0700200
Kenny Root07714d42011-08-17 17:49:28 -0700201 // Disable this since it messes up long-running cryptfs operations.
202 private static final boolean WATCHDOG_ENABLE = false;
203
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 private static final String TAG = "MountService";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700205
Jeff Sharkey9756d752015-05-14 21:07:42 -0700206 private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700207 private static final String TAG_STORAGE_TRIM = "storage_trim";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208
Kenny Root305bcbf2010-09-03 07:56:38 -0700209 private static final String VOLD_TAG = "VoldConnector";
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700210 private static final String CRYPTD_TAG = "CryptdConnector";
Kenny Root305bcbf2010-09-03 07:56:38 -0700211
Kenny Rootcf0b38c2011-03-22 14:17:59 -0700212 /** Maximum number of ASEC containers allowed to be mounted. */
213 private static final int MAX_CONTAINERS = 250;
214
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700215 /** Magic value sent by MoveTask.cpp */
216 private static final int MOVE_STATUS_COPY_FINISHED = 82;
217
San Mehat4270e1e2010-01-29 05:32:19 -0800218 /*
219 * Internal vold response code constants
220 */
San Mehat22dd86e2010-01-12 12:21:18 -0800221 class VoldResponseCode {
San Mehat4270e1e2010-01-29 05:32:19 -0800222 /*
223 * 100 series - Requestion action was initiated; expect another reply
224 * before proceeding with a new command.
225 */
San Mehat22dd86e2010-01-12 12:21:18 -0800226 public static final int VolumeListResult = 110;
227 public static final int AsecListResult = 111;
San Mehatc1b4ce92010-02-16 17:13:03 -0800228 public static final int StorageUsersListResult = 112;
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700229 public static final int CryptfsGetfieldResult = 113;
San Mehat22dd86e2010-01-12 12:21:18 -0800230
San Mehat4270e1e2010-01-29 05:32:19 -0800231 /*
232 * 200 series - Requestion action has been successfully completed.
233 */
234 public static final int ShareStatusResult = 210;
San Mehat22dd86e2010-01-12 12:21:18 -0800235 public static final int AsecPathResult = 211;
San Mehat4270e1e2010-01-29 05:32:19 -0800236 public static final int ShareEnabledResult = 212;
San Mehat22dd86e2010-01-12 12:21:18 -0800237
San Mehat4270e1e2010-01-29 05:32:19 -0800238 /*
239 * 400 series - Command was accepted, but the requested action
240 * did not take place.
241 */
242 public static final int OpFailedNoMedia = 401;
243 public static final int OpFailedMediaBlank = 402;
244 public static final int OpFailedMediaCorrupt = 403;
245 public static final int OpFailedVolNotMounted = 404;
San Mehatd9709982010-02-18 11:43:03 -0800246 public static final int OpFailedStorageBusy = 405;
San Mehat2d66cef2010-03-23 11:12:52 -0700247 public static final int OpFailedStorageNotFound = 406;
San Mehat4270e1e2010-01-29 05:32:19 -0800248
249 /*
250 * 600 series - Unsolicited broadcasts.
251 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700252 public static final int DISK_CREATED = 640;
253 public static final int DISK_SIZE_CHANGED = 641;
254 public static final int DISK_LABEL_CHANGED = 642;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700255 public static final int DISK_SCANNED = 643;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700256 public static final int DISK_SYS_PATH_CHANGED = 644;
Jeff Sharkey48877892015-03-18 11:27:19 -0700257 public static final int DISK_DESTROYED = 649;
258
259 public static final int VOLUME_CREATED = 650;
260 public static final int VOLUME_STATE_CHANGED = 651;
261 public static final int VOLUME_FS_TYPE_CHANGED = 652;
262 public static final int VOLUME_FS_UUID_CHANGED = 653;
263 public static final int VOLUME_FS_LABEL_CHANGED = 654;
264 public static final int VOLUME_PATH_CHANGED = 655;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700265 public static final int VOLUME_INTERNAL_PATH_CHANGED = 656;
Jeff Sharkey48877892015-03-18 11:27:19 -0700266 public static final int VOLUME_DESTROYED = 659;
Svetoslavf23b64d2013-04-25 14:45:54 -0700267
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700268 public static final int MOVE_STATUS = 660;
Jeff Sharkey9756d752015-05-14 21:07:42 -0700269 public static final int BENCHMARK_RESULT = 661;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700270 public static final int TRIM_RESULT = 662;
San Mehat22dd86e2010-01-12 12:21:18 -0800271 }
272
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700273 private static final int VERSION_INIT = 1;
274 private static final int VERSION_ADD_PRIMARY = 2;
Jeff Sharkeyfced5342015-05-10 14:53:34 -0700275 private static final int VERSION_FIX_PRIMARY = 3;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700276
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700277 private static final String TAG_VOLUMES = "volumes";
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700278 private static final String ATTR_VERSION = "version";
279 private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid";
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700280 private static final String ATTR_FORCE_ADOPTABLE = "forceAdoptable";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700281 private static final String TAG_VOLUME = "volume";
282 private static final String ATTR_TYPE = "type";
283 private static final String ATTR_FS_UUID = "fsUuid";
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700284 private static final String ATTR_PART_GUID = "partGuid";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700285 private static final String ATTR_NICKNAME = "nickname";
286 private static final String ATTR_USER_FLAGS = "userFlags";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700287 private static final String ATTR_CREATED_MILLIS = "createdMillis";
288 private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis";
289 private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700290
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700291 private final AtomicFile mSettingsFile;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700292
Jeff Sharkey48877892015-03-18 11:27:19 -0700293 /**
294 * <em>Never</em> hold the lock while performing downcalls into vold, since
295 * unsolicited events can suddenly appear to update data structures.
296 */
297 private final Object mLock = new Object();
298
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700299 /** Set of users that we know are unlocked. */
Jeff Sharkey48877892015-03-18 11:27:19 -0700300 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700301 private int[] mLocalUnlockedUsers = EmptyArray.INT;
302 /** Set of users that system knows are unlocked. */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800303 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700304 private int[] mSystemUnlockedUsers = EmptyArray.INT;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700305
306 /** Map from disk ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700307 @GuardedBy("mLock")
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700308 private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700309 /** Map from volume ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700310 @GuardedBy("mLock")
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700311 private final ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
Jeff Sharkey48877892015-03-18 11:27:19 -0700312
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700313 /** Map from UUID to record */
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700314 @GuardedBy("mLock")
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700315 private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>();
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700316 @GuardedBy("mLock")
317 private String mPrimaryStorageUuid;
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700318 @GuardedBy("mLock")
319 private boolean mForceAdoptable;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700320
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700321 /** Map from disk ID to latches */
322 @GuardedBy("mLock")
323 private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
324
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700325 @GuardedBy("mLock")
326 private IPackageMoveObserver mMoveCallback;
327 @GuardedBy("mLock")
328 private String mMoveTargetUuid;
329
Jeff Sharkeyab15c392016-05-05 11:45:01 -0600330 private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
331
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700332 private VolumeInfo findVolumeByIdOrThrow(String id) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700333 synchronized (mLock) {
334 final VolumeInfo vol = mVolumes.get(id);
335 if (vol != null) {
336 return vol;
337 }
338 }
339 throw new IllegalArgumentException("No volume found for ID " + id);
340 }
341
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700342 private String findVolumeIdForPathOrThrow(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700343 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700344 for (int i = 0; i < mVolumes.size(); i++) {
345 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700346 if (vol.path != null && path.startsWith(vol.path)) {
347 return vol.id;
Jeff Sharkey48877892015-03-18 11:27:19 -0700348 }
349 }
350 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700351 throw new IllegalArgumentException("No volume found for path " + path);
Jeff Sharkey48877892015-03-18 11:27:19 -0700352 }
353
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700354 private VolumeRecord findRecordForPath(String path) {
355 synchronized (mLock) {
356 for (int i = 0; i < mVolumes.size(); i++) {
357 final VolumeInfo vol = mVolumes.valueAt(i);
358 if (vol.path != null && path.startsWith(vol.path)) {
359 return mRecords.get(vol.fsUuid);
360 }
361 }
362 }
363 return null;
364 }
365
366 private String scrubPath(String path) {
367 if (path.startsWith(Environment.getDataDirectory().getAbsolutePath())) {
368 return "internal";
369 }
370 final VolumeRecord rec = findRecordForPath(path);
371 if (rec == null || rec.createdMillis == 0) {
372 return "unknown";
373 } else {
374 return "ext:" + (int) ((System.currentTimeMillis() - rec.createdMillis)
375 / DateUtils.WEEK_IN_MILLIS) + "w";
376 }
377 }
378
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700379 private @Nullable VolumeInfo findStorageForUuid(String volumeUuid) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700380 final StorageManager storage = mContext.getSystemService(StorageManager.class);
381 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700382 return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL);
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700383 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
384 return storage.getPrimaryPhysicalVolume();
385 } else {
386 return storage.findEmulatedForPrivate(storage.findVolumeByUuid(volumeUuid));
387 }
388 }
389
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700390 private boolean shouldBenchmark() {
391 final long benchInterval = Settings.Global.getLong(mContext.getContentResolver(),
392 Settings.Global.STORAGE_BENCHMARK_INTERVAL, DateUtils.WEEK_IN_MILLIS);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700393 if (benchInterval == -1) {
394 return false;
395 } else if (benchInterval == 0) {
396 return true;
397 }
398
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700399 synchronized (mLock) {
400 for (int i = 0; i < mVolumes.size(); i++) {
401 final VolumeInfo vol = mVolumes.valueAt(i);
402 final VolumeRecord rec = mRecords.get(vol.fsUuid);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700403 if (vol.isMountedWritable() && rec != null) {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700404 final long benchAge = System.currentTimeMillis() - rec.lastBenchMillis;
405 if (benchAge >= benchInterval) {
406 return true;
407 }
408 }
409 }
410 return false;
411 }
412 }
413
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700414 private CountDownLatch findOrCreateDiskScanLatch(String diskId) {
415 synchronized (mLock) {
416 CountDownLatch latch = mDiskScanLatches.get(diskId);
417 if (latch == null) {
418 latch = new CountDownLatch(1);
419 mDiskScanLatches.put(diskId, latch);
420 }
421 return latch;
422 }
423 }
424
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800425 private static String escapeNull(String arg) {
426 if (TextUtils.isEmpty(arg)) {
427 return "!";
428 } else {
429 if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
430 throw new IllegalArgumentException(arg);
431 }
432 return arg;
433 }
434 }
435
Paul Lawrence8e397362014-01-27 15:22:30 -0800436 /** List of crypto types.
437 * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
438 * corresponding commands in CommandListener.cpp */
439 public static final String[] CRYPTO_TYPES
440 = { "password", "default", "pattern", "pin" };
441
Brian Carlstrom7395a8a2014-04-28 22:11:01 -0700442 private final Context mContext;
Jeff Sharkeycd575992016-03-29 14:12:49 -0600443
Brian Carlstromdfad99a2014-05-07 15:21:14 -0700444 private final NativeDaemonConnector mConnector;
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700445 private final NativeDaemonConnector mCryptConnector;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700446
Jeff Sharkeycd575992016-03-29 14:12:49 -0600447 private final Thread mConnectorThread;
448 private final Thread mCryptConnectorThread;
449
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700450 private volatile boolean mSystemReady = false;
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900451 private volatile boolean mBootCompleted = false;
Jeff Sharkey48877892015-03-18 11:27:19 -0700452 private volatile boolean mDaemonConnected = false;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700453
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700454 private PackageManagerService mPms;
455
456 private final Callbacks mCallbacks;
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700457 private final LockPatternUtils mLockPatternUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -0700458
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700459 // Two connectors - mConnector & mCryptConnector
460 private final CountDownLatch mConnectedSignal = new CountDownLatch(2);
Jeff Sharkey0be607c2012-11-14 14:39:19 -0800461 private final CountDownLatch mAsecsScanned = new CountDownLatch(1);
Jeff Sharkey48877892015-03-18 11:27:19 -0700462
463 private final Object mUnmountLock = new Object();
464 @GuardedBy("mUnmountLock")
465 private CountDownLatch mUnmountSignal;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800466
San Mehat6cdd9c02010-02-09 14:45:20 -0800467 /**
468 * Private hash of currently mounted secure containers.
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800469 * Used as a lock in methods to manipulate secure containers.
San Mehat6cdd9c02010-02-09 14:45:20 -0800470 */
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800471 final private HashSet<String> mAsecMountSet = new HashSet<String>();
San Mehat6cdd9c02010-02-09 14:45:20 -0800472
Kenny Root02c87302010-07-01 08:10:18 -0700473 /**
Kenny Root3b1abba2010-10-13 15:00:07 -0700474 * The size of the crypto algorithm key in bits for OBB files. Currently
475 * Twofish is used which takes 128-bit keys.
476 */
477 private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
478
479 /**
480 * The number of times to run SHA1 in the PBKDF2 function for OBB files.
481 * 1024 is reasonably secure and not too slow.
482 */
483 private static final int PBKDF2_HASH_ROUNDS = 1024;
484
485 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700486 * Mounted OBB tracking information. Used to track the current state of all
487 * OBBs.
Kenny Root02c87302010-07-01 08:10:18 -0700488 */
Kenny Root735de3b2010-09-30 14:11:39 -0700489 final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700490
491 /** Map from raw paths to {@link ObbState}. */
Kenny Roota02b8b02010-08-05 16:14:17 -0700492 final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
493
Svet Ganov6ee871e2015-07-10 14:29:33 -0700494 // Not guarded by a lock.
495 private final MountServiceInternalImpl mMountServiceInternal = new MountServiceInternalImpl();
496
Kenny Roota02b8b02010-08-05 16:14:17 -0700497 class ObbState implements IBinder.DeathRecipient {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700498 public ObbState(String rawPath, String canonicalPath, int callingUid,
499 IObbActionListener token, int nonce) {
500 this.rawPath = rawPath;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700501 this.canonicalPath = canonicalPath;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700502
503 this.ownerGid = UserHandle.getSharedAppGid(callingUid);
Kenny Rootaf9d6672010-10-08 09:21:39 -0700504 this.token = token;
505 this.nonce = nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700506 }
507
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700508 final String rawPath;
509 final String canonicalPath;
Kenny Roota02b8b02010-08-05 16:14:17 -0700510
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700511 final int ownerGid;
Kenny Roota02b8b02010-08-05 16:14:17 -0700512
Kenny Rootaf9d6672010-10-08 09:21:39 -0700513 // Token of remote Binder caller
514 final IObbActionListener token;
515
516 // Identifier to pass back to the token
517 final int nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700518
Kenny Root735de3b2010-09-30 14:11:39 -0700519 public IBinder getBinder() {
520 return token.asBinder();
521 }
522
Kenny Roota02b8b02010-08-05 16:14:17 -0700523 @Override
524 public void binderDied() {
525 ObbAction action = new UnmountObbAction(this, true);
526 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root735de3b2010-09-30 14:11:39 -0700527 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700528
Kenny Root5919ac62010-10-05 09:49:40 -0700529 public void link() throws RemoteException {
530 getBinder().linkToDeath(this, 0);
531 }
532
533 public void unlink() {
Kenny Root735de3b2010-09-30 14:11:39 -0700534 getBinder().unlinkToDeath(this, 0);
Kenny Roota02b8b02010-08-05 16:14:17 -0700535 }
Kenny Root38cf8862010-09-26 14:18:51 -0700536
537 @Override
538 public String toString() {
539 StringBuilder sb = new StringBuilder("ObbState{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700540 sb.append("rawPath=").append(rawPath);
541 sb.append(",canonicalPath=").append(canonicalPath);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700542 sb.append(",ownerGid=").append(ownerGid);
543 sb.append(",token=").append(token);
544 sb.append(",binder=").append(getBinder());
Kenny Root38cf8862010-09-26 14:18:51 -0700545 sb.append('}');
546 return sb.toString();
547 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700548 }
549
550 // OBB Action Handler
551 final private ObbActionHandler mObbActionHandler;
552
553 // OBB action handler messages
554 private static final int OBB_RUN_ACTION = 1;
555 private static final int OBB_MCS_BOUND = 2;
556 private static final int OBB_MCS_UNBIND = 3;
557 private static final int OBB_MCS_RECONNECT = 4;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700558 private static final int OBB_FLUSH_MOUNT_STATE = 5;
Kenny Roota02b8b02010-08-05 16:14:17 -0700559
560 /*
561 * Default Container Service information
562 */
563 static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
564 "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
565
566 final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
567
568 class DefaultContainerConnection implements ServiceConnection {
Jeff Sharkey48877892015-03-18 11:27:19 -0700569 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700570 public void onServiceConnected(ComponentName name, IBinder service) {
571 if (DEBUG_OBB)
572 Slog.i(TAG, "onServiceConnected");
573 IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
574 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
575 }
576
Jeff Sharkey48877892015-03-18 11:27:19 -0700577 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700578 public void onServiceDisconnected(ComponentName name) {
579 if (DEBUG_OBB)
580 Slog.i(TAG, "onServiceDisconnected");
581 }
582 };
583
584 // Used in the ObbActionHandler
585 private IMediaContainerService mContainerService = null;
Kenny Root02c87302010-07-01 08:10:18 -0700586
Christopher Tate7265abe2014-11-21 13:54:45 -0800587 // Last fstrim operation tracking
588 private static final String LAST_FSTRIM_FILE = "last-fstrim";
589 private final File mLastMaintenanceFile;
590 private long mLastMaintenance;
591
Kenny Root02c87302010-07-01 08:10:18 -0700592 // Handler messages
Jeff Sharkey48877892015-03-18 11:27:19 -0700593 private static final int H_SYSTEM_READY = 1;
594 private static final int H_DAEMON_CONNECTED = 2;
595 private static final int H_SHUTDOWN = 3;
596 private static final int H_FSTRIM = 4;
597 private static final int H_VOLUME_MOUNT = 5;
598 private static final int H_VOLUME_BROADCAST = 6;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700599 private static final int H_INTERNAL_BROADCAST = 7;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700600 private static final int H_VOLUME_UNMOUNT = 8;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800601 private static final int H_PARTITION_FORGET = 9;
602 private static final int H_RESET = 10;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800603
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400604 class MountServiceHandler extends Handler {
Jeff Sharkey48877892015-03-18 11:27:19 -0700605 public MountServiceHandler(Looper looper) {
606 super(looper);
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400607 }
608
Jason parks5af0b912010-11-29 09:05:25 -0600609 @Override
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800610 public void handleMessage(Message msg) {
611 switch (msg.what) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700612 case H_SYSTEM_READY: {
Jeff Sharkey48877892015-03-18 11:27:19 -0700613 handleSystemReady();
614 break;
615 }
616 case H_DAEMON_CONNECTED: {
617 handleDaemonConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700618 break;
619 }
Christopher Tated417d622013-08-19 16:14:25 -0700620 case H_FSTRIM: {
Jeff Sharkey1783f142015-04-17 10:52:51 -0700621 if (!isReady()) {
622 Slog.i(TAG, "fstrim requested, but no daemon connection yet; trying again");
Christopher Tate7618db12015-04-28 16:32:55 -0700623 sendMessageDelayed(obtainMessage(H_FSTRIM, msg.obj),
624 DateUtils.SECOND_IN_MILLIS);
625 break;
Jeff Sharkey1783f142015-04-17 10:52:51 -0700626 }
627
Christopher Tated417d622013-08-19 16:14:25 -0700628 Slog.i(TAG, "Running fstrim idle maintenance");
Christopher Tate7265abe2014-11-21 13:54:45 -0800629
630 // Remember when we kicked it off
631 try {
632 mLastMaintenance = System.currentTimeMillis();
633 mLastMaintenanceFile.setLastModified(mLastMaintenance);
634 } catch (Exception e) {
635 Slog.e(TAG, "Unable to record last fstrim!");
636 }
637
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700638 final boolean shouldBenchmark = shouldBenchmark();
Christopher Tated417d622013-08-19 16:14:25 -0700639 try {
640 // This method must be run on the main (handler) thread,
641 // so it is safe to directly call into vold.
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700642 mConnector.execute("fstrim", shouldBenchmark ? "dotrimbench" : "dotrim");
Christopher Tated417d622013-08-19 16:14:25 -0700643 } catch (NativeDaemonConnectorException ndce) {
644 Slog.e(TAG, "Failed to run fstrim!");
645 }
Christopher Tate7265abe2014-11-21 13:54:45 -0800646
Christopher Tated417d622013-08-19 16:14:25 -0700647 // invoke the completion callback, if any
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700648 // TODO: fstrim is non-blocking, so remove this useless callback
Christopher Tated417d622013-08-19 16:14:25 -0700649 Runnable callback = (Runnable) msg.obj;
650 if (callback != null) {
651 callback.run();
652 }
653 break;
654 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700655 case H_SHUTDOWN: {
656 final IMountShutdownObserver obs = (IMountShutdownObserver) msg.obj;
657 boolean success = false;
658 try {
659 success = mConnector.execute("volume", "shutdown").isClassOk();
660 } catch (NativeDaemonConnectorException ignored) {
661 }
662 if (obs != null) {
663 try {
664 obs.onShutDownComplete(success ? 0 : -1);
665 } catch (RemoteException ignored) {
666 }
667 }
668 break;
669 }
670 case H_VOLUME_MOUNT: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700671 final VolumeInfo vol = (VolumeInfo) msg.obj;
Jeff Sharkey2e606d72015-07-27 14:19:54 -0700672 if (isMountDisallowed(vol)) {
673 Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");
674 break;
675 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700676 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700677 mConnector.execute("volume", "mount", vol.id, vol.mountFlags,
678 vol.mountUserId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700679 } catch (NativeDaemonConnectorException ignored) {
680 }
681 break;
682 }
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700683 case H_VOLUME_UNMOUNT: {
684 final VolumeInfo vol = (VolumeInfo) msg.obj;
685 unmount(vol.getId());
686 break;
687 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700688 case H_VOLUME_BROADCAST: {
689 final StorageVolume userVol = (StorageVolume) msg.obj;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700690 final String envState = userVol.getState();
691 Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + envState + " to "
Jeff Sharkey48877892015-03-18 11:27:19 -0700692 + userVol.getOwner());
693
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700694 final String action = VolumeInfo.getBroadcastForEnvironment(envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700695 if (action != null) {
696 final Intent intent = new Intent(action,
697 Uri.fromFile(userVol.getPathFile()));
698 intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, userVol);
699 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
700 mContext.sendBroadcastAsUser(intent, userVol.getOwner());
701 }
702 break;
703 }
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700704 case H_INTERNAL_BROADCAST: {
705 // Internal broadcasts aimed at system components, not for
706 // third-party apps.
707 final Intent intent = (Intent) msg.obj;
708 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
709 android.Manifest.permission.WRITE_MEDIA_STORAGE);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800710 break;
711 }
712 case H_PARTITION_FORGET: {
713 final String partGuid = (String) msg.obj;
714 forgetPartition(partGuid);
715 break;
716 }
717 case H_RESET: {
718 resetIfReadyAndConnected();
719 break;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700720 }
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800721 }
722 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700723 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700724
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700725 private final Handler mHandler;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800726
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700727 private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
728 @Override
729 public void onReceive(Context context, Intent intent) {
730 final String action = intent.getAction();
731 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700732 Preconditions.checkArgument(userId >= 0);
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700733
734 try {
735 if (Intent.ACTION_USER_ADDED.equals(action)) {
736 final UserManager um = mContext.getSystemService(UserManager.class);
737 final int userSerialNumber = um.getUserSerialNumber(userId);
738 mConnector.execute("volume", "user_added", userId, userSerialNumber);
739 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700740 synchronized (mVolumes) {
741 final int size = mVolumes.size();
742 for (int i = 0; i < size; i++) {
743 final VolumeInfo vol = mVolumes.valueAt(i);
744 if (vol.mountUserId == userId) {
745 vol.mountUserId = UserHandle.USER_NULL;
746 mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
747 }
748 }
749 }
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700750 mConnector.execute("volume", "user_removed", userId);
751 }
752 } catch (NativeDaemonConnectorException e) {
753 Slog.w(TAG, "Failed to send user details to vold", e);
754 }
755 }
756 };
757
Jeff Sharkey56e62932015-03-21 20:41:00 -0700758 @Override
759 public void waitForAsecScan() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700760 waitForLatch(mAsecsScanned, "mAsecsScanned");
Kenny Root51a573c2012-05-17 13:30:28 -0700761 }
762
San Mehat207e5382010-02-04 20:46:54 -0800763 private void waitForReady() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700764 waitForLatch(mConnectedSignal, "mConnectedSignal");
Kenny Root51a573c2012-05-17 13:30:28 -0700765 }
766
Jeff Sharkey48877892015-03-18 11:27:19 -0700767 private void waitForLatch(CountDownLatch latch, String condition) {
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700768 try {
769 waitForLatch(latch, condition, -1);
770 } catch (TimeoutException ignored) {
771 }
772 }
773
774 private void waitForLatch(CountDownLatch latch, String condition, long timeoutMillis)
775 throws TimeoutException {
776 final long startMillis = SystemClock.elapsedRealtime();
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700777 while (true) {
Kenny Root51a573c2012-05-17 13:30:28 -0700778 try {
779 if (latch.await(5000, TimeUnit.MILLISECONDS)) {
San Mehat207e5382010-02-04 20:46:54 -0800780 return;
Kenny Root51a573c2012-05-17 13:30:28 -0700781 } else {
782 Slog.w(TAG, "Thread " + Thread.currentThread().getName()
Jeff Sharkey48877892015-03-18 11:27:19 -0700783 + " still waiting for " + condition + "...");
San Mehat207e5382010-02-04 20:46:54 -0800784 }
Kenny Root51a573c2012-05-17 13:30:28 -0700785 } catch (InterruptedException e) {
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700786 Slog.w(TAG, "Interrupt while waiting for " + condition);
San Mehat207e5382010-02-04 20:46:54 -0800787 }
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700788 if (timeoutMillis > 0 && SystemClock.elapsedRealtime() > startMillis + timeoutMillis) {
789 throw new TimeoutException("Thread " + Thread.currentThread().getName()
790 + " gave up waiting for " + condition + " after " + timeoutMillis + "ms");
791 }
San Mehat207e5382010-02-04 20:46:54 -0800792 }
San Mehat1f6301e2010-01-07 22:40:27 -0800793 }
Kenny Root02c87302010-07-01 08:10:18 -0700794
Paul Lawrence945490c2014-03-27 16:37:28 +0000795 private boolean isReady() {
796 try {
797 return mConnectedSignal.await(0, TimeUnit.MILLISECONDS);
798 } catch (InterruptedException e) {
799 return false;
800 }
801 }
802
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700803 private void handleSystemReady() {
Jeff Sharkey8924e872015-11-30 12:52:10 -0700804 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800805 resetIfReadyAndConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700806
Jeff Sharkey48877892015-03-18 11:27:19 -0700807 // Start scheduling nominally-daily fstrim operations
Christopher Tate115afda2014-06-06 19:06:26 -0700808 MountServiceIdler.scheduleIdlePass(mContext);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700809 }
810
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700811 /**
812 * MediaProvider has a ton of code that makes assumptions about storage
813 * paths never changing, so we outright kill them to pick up new state.
814 */
815 @Deprecated
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700816 private void killMediaProvider(List<UserInfo> users) {
817 if (users == null) return;
818
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700819 final long token = Binder.clearCallingIdentity();
820 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700821 for (UserInfo user : users) {
822 // System user does not have media provider, so skip.
823 if (user.isSystemOnly()) continue;
824
Jeff Sharkey2a9e3f82015-12-18 10:57:58 -0700825 final ProviderInfo provider = mPms.resolveContentProvider(MediaStore.AUTHORITY,
Jeff Sharkey8a372a02016-03-16 16:25:45 -0600826 PackageManager.MATCH_DIRECT_BOOT_AWARE
827 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
828 user.id);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700829 if (provider != null) {
830 final IActivityManager am = ActivityManagerNative.getDefault();
831 try {
Jeff Sharkey85f449e2016-06-23 09:26:00 -0600832 am.killApplication(provider.applicationInfo.packageName,
833 UserHandle.getAppId(provider.applicationInfo.uid),
834 UserHandle.USER_ALL, "vold reset");
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700835 // We only need to run this once. It will kill all users' media processes.
836 break;
837 } catch (RemoteException e) {
838 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700839 }
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700840 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700841 } finally {
842 Binder.restoreCallingIdentity(token);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700843 }
844 }
845
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800846 private void addInternalVolumeLocked() {
Amith Yamasania7892482015-08-07 11:09:05 -0700847 // Create a stub volume that represents internal storage
848 final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
849 VolumeInfo.TYPE_PRIVATE, null, null);
850 internal.state = VolumeInfo.STATE_MOUNTED;
851 internal.path = Environment.getDataDirectory().getAbsolutePath();
852 mVolumes.put(internal.id, internal);
853 }
854
Jeff Sharkey8924e872015-11-30 12:52:10 -0700855 private void initIfReadyAndConnected() {
856 Slog.d(TAG, "Thinking about init, mSystemReady=" + mSystemReady
857 + ", mDaemonConnected=" + mDaemonConnected);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700858 if (mSystemReady && mDaemonConnected
Paul Lawrence20be5d62016-02-26 13:51:17 -0800859 && !StorageManager.isFileEncryptedNativeOnly()) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700860 // When booting a device without native support, make sure that our
861 // user directories are locked or unlocked based on the current
862 // emulation status.
Paul Lawrence20be5d62016-02-26 13:51:17 -0800863 final boolean initLocked = StorageManager.isFileEncryptedEmulatedOnly();
Paul Crowleyd94ab732016-02-15 06:44:51 +0000864 Slog.d(TAG, "Setting up emulation state, initlocked=" + initLocked);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700865 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Jeff Sharkey8924e872015-11-30 12:52:10 -0700866 for (UserInfo user : users) {
867 try {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700868 if (initLocked) {
869 mCryptConnector.execute("cryptfs", "lock_user_key", user.id);
870 } else {
871 mCryptConnector.execute("cryptfs", "unlock_user_key", user.id,
Paul Crowleyd94ab732016-02-15 06:44:51 +0000872 user.serialNumber, "!", "!");
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700873 }
Jeff Sharkey8924e872015-11-30 12:52:10 -0700874 } catch (NativeDaemonConnectorException e) {
875 Slog.w(TAG, "Failed to init vold", e);
876 }
877 }
878 }
879 }
880
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800881 private void resetIfReadyAndConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700882 Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
883 + ", mDaemonConnected=" + mDaemonConnected);
884 if (mSystemReady && mDaemonConnected) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800885 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700886 killMediaProvider(users);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700887
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700888 final int[] systemUnlockedUsers;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800889 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700890 systemUnlockedUsers = mSystemUnlockedUsers;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700891
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800892 mDisks.clear();
893 mVolumes.clear();
894
895 addInternalVolumeLocked();
896 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700897
Jeff Sharkey48877892015-03-18 11:27:19 -0700898 try {
899 mConnector.execute("volume", "reset");
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700900
901 // Tell vold about all existing and started users
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700902 for (UserInfo user : users) {
903 mConnector.execute("volume", "user_added", user.id, user.serialNumber);
904 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700905 for (int userId : systemUnlockedUsers) {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700906 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey50a05452015-04-29 11:24:52 -0700907 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700908 } catch (NativeDaemonConnectorException e) {
909 Slog.w(TAG, "Failed to reset vold", e);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700910 }
911 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700912 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700913
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700914 private void onUnlockUser(int userId) {
915 Slog.d(TAG, "onUnlockUser " + userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700916
917 // We purposefully block here to make sure that user-specific
918 // staging area is ready so it's ready for zygote-forked apps to
919 // bind mount against.
920 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700921 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700922 } catch (NativeDaemonConnectorException ignored) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700923 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700924
925 // Record user as started so newly mounted volumes kick off events
926 // correctly, then synthesize events for any already-mounted volumes.
yuanhuihuiefd1f122016-07-13 21:21:03 +0800927 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700928 for (int i = 0; i < mVolumes.size(); i++) {
929 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey46349872015-07-28 10:49:47 -0700930 if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700931 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey48877892015-03-18 11:27:19 -0700932 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700933
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700934 final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
935 mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700936 }
937 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700938 mSystemUnlockedUsers = ArrayUtils.appendInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700939 }
940 }
941
942 private void onCleanupUser(int userId) {
943 Slog.d(TAG, "onCleanupUser " + userId);
944
945 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700946 mConnector.execute("volume", "user_stopped", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700947 } catch (NativeDaemonConnectorException ignored) {
948 }
949
yuanhuihuiefd1f122016-07-13 21:21:03 +0800950 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700951 mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700952 }
953 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700954
Christopher Tated417d622013-08-19 16:14:25 -0700955 void runIdleMaintenance(Runnable callback) {
956 mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
957 }
958
Christopher Tate7265abe2014-11-21 13:54:45 -0800959 // Binder entry point for kicking off an immediate fstrim
960 @Override
961 public void runMaintenance() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700962 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Christopher Tate7265abe2014-11-21 13:54:45 -0800963 runIdleMaintenance(null);
964 }
965
966 @Override
967 public long lastMaintenance() {
968 return mLastMaintenance;
969 }
970
San Mehat4270e1e2010-01-29 05:32:19 -0800971 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800972 * Callback from NativeDaemonConnector
973 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700974 @Override
San Mehat4270e1e2010-01-29 05:32:19 -0800975 public void onDaemonConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700976 mDaemonConnected = true;
977 mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();
978 }
979
980 private void handleDaemonConnected() {
Jeff Sharkey8924e872015-11-30 12:52:10 -0700981 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800982 resetIfReadyAndConnected();
Jeff Sharkey48877892015-03-18 11:27:19 -0700983
San Mehat4270e1e2010-01-29 05:32:19 -0800984 /*
Jeff Sharkey48877892015-03-18 11:27:19 -0700985 * Now that we've done our initialization, release
986 * the hounds!
San Mehat4270e1e2010-01-29 05:32:19 -0800987 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700988 mConnectedSignal.countDown();
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700989 if (mConnectedSignal.getCount() != 0) {
990 // More daemons need to connect
991 return;
992 }
Mike Lockwood7fa24aa2011-03-23 14:52:34 -0400993
Jeff Sharkey48877892015-03-18 11:27:19 -0700994 // On an encrypted device we can't see system properties yet, so pull
995 // the system locale out of the mount service.
996 if ("".equals(SystemProperties.get("vold.encrypt_progress"))) {
997 copyLocaleFromMountService();
998 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700999
Jeff Sharkey48877892015-03-18 11:27:19 -07001000 // Let package manager load internal ASECs.
1001 mPms.scanAvailableAsecs();
Mike Lockwood7fa24aa2011-03-23 14:52:34 -04001002
Jeff Sharkey48877892015-03-18 11:27:19 -07001003 // Notify people waiting for ASECs to be scanned that it's done.
1004 mAsecsScanned.countDown();
San Mehat4270e1e2010-01-29 05:32:19 -08001005 }
1006
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001007 private void copyLocaleFromMountService() {
1008 String systemLocale;
1009 try {
1010 systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
1011 } catch (RemoteException e) {
1012 return;
1013 }
1014 if (TextUtils.isEmpty(systemLocale)) {
1015 return;
1016 }
1017
1018 Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
1019 Locale locale = Locale.forLanguageTag(systemLocale);
1020 Configuration config = new Configuration();
1021 config.setLocale(locale);
1022 try {
Seigo Nonaka4963dfe2016-03-31 20:50:21 +09001023 ActivityManagerNative.getDefault().updatePersistentConfiguration(config);
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001024 } catch (RemoteException e) {
1025 Slog.e(TAG, "Error setting system locale from mount service", e);
1026 }
Elliott Hughes9c33f282014-10-13 12:39:56 -07001027
1028 // Temporary workaround for http://b/17945169.
1029 Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
Narayan Kamathd30dbb82015-01-15 14:48:15 +00001030 SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001031 }
1032
San Mehat4270e1e2010-01-29 05:32:19 -08001033 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001034 * Callback from NativeDaemonConnector
1035 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001036 @Override
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001037 public boolean onCheckHoldWakeLock(int code) {
1038 return false;
1039 }
1040
1041 /**
1042 * Callback from NativeDaemonConnector
1043 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001044 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001045 public boolean onEvent(int code, String raw, String[] cooked) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001046 synchronized (mLock) {
1047 return onEventLocked(code, raw, cooked);
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -08001048 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001049 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001050
Jeff Sharkey48877892015-03-18 11:27:19 -07001051 private boolean onEventLocked(int code, String raw, String[] cooked) {
1052 switch (code) {
1053 case VoldResponseCode.DISK_CREATED: {
1054 if (cooked.length != 3) break;
1055 final String id = cooked[1];
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001056 int flags = Integer.parseInt(cooked[2]);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001057 if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false)
1058 || mForceAdoptable) {
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001059 flags |= DiskInfo.FLAG_ADOPTABLE;
1060 }
Jeff Sharkey6ed74182016-08-23 13:53:53 -06001061 // Adoptable storage isn't currently supported on FBE devices
1062 if (StorageManager.isFileEncryptedNativeOnly()) {
1063 flags &= ~DiskInfo.FLAG_ADOPTABLE;
1064 }
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001065 mDisks.put(id, new DiskInfo(id, flags));
Jeff Sharkey48877892015-03-18 11:27:19 -07001066 break;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001067 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001068 case VoldResponseCode.DISK_SIZE_CHANGED: {
1069 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001070 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001071 if (disk != null) {
1072 disk.size = Long.parseLong(cooked[2]);
San Mehat4270e1e2010-01-29 05:32:19 -08001073 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001074 break;
1075 }
1076 case VoldResponseCode.DISK_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001077 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001078 if (disk != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001079 final StringBuilder builder = new StringBuilder();
1080 for (int i = 2; i < cooked.length; i++) {
1081 builder.append(cooked[i]).append(' ');
1082 }
1083 disk.label = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001084 }
1085 break;
1086 }
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001087 case VoldResponseCode.DISK_SCANNED: {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001088 if (cooked.length != 2) break;
1089 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001090 if (disk != null) {
1091 onDiskScannedLocked(disk);
1092 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -07001093 break;
1094 }
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001095 case VoldResponseCode.DISK_SYS_PATH_CHANGED: {
1096 if (cooked.length != 3) break;
1097 final DiskInfo disk = mDisks.get(cooked[1]);
1098 if (disk != null) {
1099 disk.sysPath = cooked[2];
1100 }
1101 break;
1102 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001103 case VoldResponseCode.DISK_DESTROYED: {
1104 if (cooked.length != 2) break;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07001105 final DiskInfo disk = mDisks.remove(cooked[1]);
1106 if (disk != null) {
1107 mCallbacks.notifyDiskDestroyed(disk);
1108 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001109 break;
1110 }
San Mehat4270e1e2010-01-29 05:32:19 -08001111
Jeff Sharkey48877892015-03-18 11:27:19 -07001112 case VoldResponseCode.VOLUME_CREATED: {
Jeff Sharkey48877892015-03-18 11:27:19 -07001113 final String id = cooked[1];
1114 final int type = Integer.parseInt(cooked[2]);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001115 final String diskId = TextUtils.nullIfEmpty(cooked[3]);
1116 final String partGuid = TextUtils.nullIfEmpty(cooked[4]);
1117
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001118 final DiskInfo disk = mDisks.get(diskId);
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07001119 final VolumeInfo vol = new VolumeInfo(id, type, disk, partGuid);
Jeff Sharkey48877892015-03-18 11:27:19 -07001120 mVolumes.put(id, vol);
1121 onVolumeCreatedLocked(vol);
1122 break;
1123 }
1124 case VoldResponseCode.VOLUME_STATE_CHANGED: {
1125 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001126 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001127 if (vol != null) {
1128 final int oldState = vol.state;
1129 final int newState = Integer.parseInt(cooked[2]);
1130 vol.state = newState;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001131 onVolumeStateChangedLocked(vol, oldState, newState);
Jeff Sharkey48877892015-03-18 11:27:19 -07001132 }
1133 break;
1134 }
1135 case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: {
1136 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001137 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001138 if (vol != null) {
1139 vol.fsType = cooked[2];
1140 }
1141 break;
1142 }
1143 case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
1144 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001145 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001146 if (vol != null) {
1147 vol.fsUuid = cooked[2];
1148 }
1149 break;
1150 }
1151 case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001152 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001153 if (vol != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001154 final StringBuilder builder = new StringBuilder();
1155 for (int i = 2; i < cooked.length; i++) {
1156 builder.append(cooked[i]).append(' ');
1157 }
1158 vol.fsLabel = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001159 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001160 // TODO: notify listeners that label changed
Jeff Sharkey48877892015-03-18 11:27:19 -07001161 break;
1162 }
1163 case VoldResponseCode.VOLUME_PATH_CHANGED: {
1164 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001165 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001166 if (vol != null) {
1167 vol.path = cooked[2];
1168 }
1169 break;
1170 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001171 case VoldResponseCode.VOLUME_INTERNAL_PATH_CHANGED: {
1172 if (cooked.length != 3) break;
1173 final VolumeInfo vol = mVolumes.get(cooked[1]);
1174 if (vol != null) {
1175 vol.internalPath = cooked[2];
1176 }
1177 break;
1178 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001179 case VoldResponseCode.VOLUME_DESTROYED: {
1180 if (cooked.length != 2) break;
1181 mVolumes.remove(cooked[1]);
1182 break;
1183 }
San Mehat4270e1e2010-01-29 05:32:19 -08001184
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001185 case VoldResponseCode.MOVE_STATUS: {
1186 final int status = Integer.parseInt(cooked[1]);
1187 onMoveStatusLocked(status);
1188 break;
1189 }
Jeff Sharkey9756d752015-05-14 21:07:42 -07001190 case VoldResponseCode.BENCHMARK_RESULT: {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001191 if (cooked.length != 7) break;
1192 final String path = cooked[1];
1193 final String ident = cooked[2];
1194 final long create = Long.parseLong(cooked[3]);
1195 final long drop = Long.parseLong(cooked[4]);
1196 final long run = Long.parseLong(cooked[5]);
1197 final long destroy = Long.parseLong(cooked[6]);
1198
Jeff Sharkey9756d752015-05-14 21:07:42 -07001199 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001200 dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
1201 + " " + ident + " " + create + " " + run + " " + destroy);
1202
1203 final VolumeRecord rec = findRecordForPath(path);
1204 if (rec != null) {
1205 rec.lastBenchMillis = System.currentTimeMillis();
1206 writeSettingsLocked();
1207 }
1208
1209 break;
1210 }
1211 case VoldResponseCode.TRIM_RESULT: {
1212 if (cooked.length != 4) break;
1213 final String path = cooked[1];
1214 final long bytes = Long.parseLong(cooked[2]);
1215 final long time = Long.parseLong(cooked[3]);
1216
1217 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
1218 dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path)
1219 + " " + bytes + " " + time);
1220
1221 final VolumeRecord rec = findRecordForPath(path);
1222 if (rec != null) {
1223 rec.lastTrimMillis = System.currentTimeMillis();
1224 writeSettingsLocked();
1225 }
1226
Jeff Sharkey9756d752015-05-14 21:07:42 -07001227 break;
1228 }
1229
Jeff Sharkey48877892015-03-18 11:27:19 -07001230 default: {
1231 Slog.d(TAG, "Unhandled vold event " + code);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001232 }
San Mehat4270e1e2010-01-29 05:32:19 -08001233 }
1234
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001235 return true;
San Mehat4270e1e2010-01-29 05:32:19 -08001236 }
1237
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001238 private void onDiskScannedLocked(DiskInfo disk) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001239 int volumeCount = 0;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001240 for (int i = 0; i < mVolumes.size(); i++) {
1241 final VolumeInfo vol = mVolumes.valueAt(i);
1242 if (Objects.equals(disk.id, vol.getDiskId())) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001243 volumeCount++;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001244 }
1245 }
1246
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001247 final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
Jeff Sharkey7732e1e2016-03-30 17:14:23 -06001248 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1249 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001250 intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
1251 intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001252 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001253
1254 final CountDownLatch latch = mDiskScanLatches.remove(disk.id);
1255 if (latch != null) {
1256 latch.countDown();
1257 }
1258
Jeff Sharkeyf5a6bd72015-05-19 14:42:38 -07001259 disk.volumeCount = volumeCount;
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001260 mCallbacks.notifyDiskScanned(disk, volumeCount);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001261 }
1262
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001263 private void onVolumeCreatedLocked(VolumeInfo vol) {
Jeff Sharkey6855c482016-03-31 14:34:38 -06001264 if (mPms.isOnlyCoreApps()) {
1265 Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId());
1266 return;
1267 }
1268
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001269 if (vol.type == VolumeInfo.TYPE_EMULATED) {
1270 final StorageManager storage = mContext.getSystemService(StorageManager.class);
1271 final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
1272
1273 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
1274 && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
1275 Slog.v(TAG, "Found primary storage at " + vol);
1276 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1277 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1278 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1279
1280 } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
1281 Slog.v(TAG, "Found primary storage at " + vol);
1282 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1283 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1284 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1285 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001286
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001287 } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001288 // TODO: only look at first public partition
1289 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1290 && vol.disk.isDefaultPrimary()) {
1291 Slog.v(TAG, "Found primary storage at " + vol);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001292 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1293 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
San Mehat4270e1e2010-01-29 05:32:19 -08001294 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001295
1296 // Adoptable public disks are visible to apps, since they meet
1297 // public API requirement of being in a stable location.
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001298 if (vol.disk.isAdoptable()) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001299 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1300 }
1301
Jeff Sharkeyab15c392016-05-05 11:45:01 -06001302 vol.mountUserId = mCurrentUserId;
Jeff Sharkey48877892015-03-18 11:27:19 -07001303 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001304
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001305 } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1306 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1307
San Mehat4270e1e2010-01-29 05:32:19 -08001308 } else {
Jeff Sharkey48877892015-03-18 11:27:19 -07001309 Slog.d(TAG, "Skipping automatic mounting of " + vol);
San Mehat4270e1e2010-01-29 05:32:19 -08001310 }
1311 }
1312
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001313 private boolean isBroadcastWorthy(VolumeInfo vol) {
1314 switch (vol.getType()) {
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001315 case VolumeInfo.TYPE_PRIVATE:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001316 case VolumeInfo.TYPE_PUBLIC:
1317 case VolumeInfo.TYPE_EMULATED:
1318 break;
1319 default:
1320 return false;
1321 }
1322
1323 switch (vol.getState()) {
1324 case VolumeInfo.STATE_MOUNTED:
1325 case VolumeInfo.STATE_MOUNTED_READ_ONLY:
1326 case VolumeInfo.STATE_EJECTING:
1327 case VolumeInfo.STATE_UNMOUNTED:
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001328 case VolumeInfo.STATE_UNMOUNTABLE:
Tony Mantlerf0d71052015-06-24 11:45:25 -07001329 case VolumeInfo.STATE_BAD_REMOVAL:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001330 break;
1331 default:
1332 return false;
1333 }
1334
1335 return true;
1336 }
1337
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001338 private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001339 // Remember that we saw this volume so we're ready to accept user
1340 // metadata, or so we can annoy them when a private volume is ejected
1341 if (vol.isMountedReadable() && !TextUtils.isEmpty(vol.fsUuid)) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001342 VolumeRecord rec = mRecords.get(vol.fsUuid);
1343 if (rec == null) {
1344 rec = new VolumeRecord(vol.type, vol.fsUuid);
1345 rec.partGuid = vol.partGuid;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001346 rec.createdMillis = System.currentTimeMillis();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001347 if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1348 rec.nickname = vol.disk.getDescription();
1349 }
1350 mRecords.put(rec.fsUuid, rec);
1351 writeSettingsLocked();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001352 } else {
1353 // Handle upgrade case where we didn't store partition GUID
1354 if (TextUtils.isEmpty(rec.partGuid)) {
1355 rec.partGuid = vol.partGuid;
1356 writeSettingsLocked();
1357 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001358 }
1359 }
1360
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001361 mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
1362
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001363 // Do not broadcast before boot has completed to avoid launching the
1364 // processes that receive the intent unnecessarily.
1365 if (mBootCompleted && isBroadcastWorthy(vol)) {
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001366 final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001367 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
1368 intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
Tony Mantlerf0d71052015-06-24 11:45:25 -07001369 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
Jeff Sharkey7732e1e2016-03-30 17:14:23 -06001370 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1371 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001372 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001373 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001374
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001375 final String oldStateEnv = VolumeInfo.getEnvironmentForState(oldState);
1376 final String newStateEnv = VolumeInfo.getEnvironmentForState(newState);
Emily Bernier92aa5a22014-07-07 10:11:48 -04001377
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001378 if (!Objects.equals(oldStateEnv, newStateEnv)) {
1379 // Kick state changed event towards all started users. Any users
1380 // started after this point will trigger additional
1381 // user-specific broadcasts.
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001382 for (int userId : mSystemUnlockedUsers) {
Jeff Sharkey46349872015-07-28 10:49:47 -07001383 if (vol.isVisibleForRead(userId)) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001384 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001385 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey48877892015-03-18 11:27:19 -07001386
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001387 mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
1388 newStateEnv);
San Mehat4270e1e2010-01-29 05:32:19 -08001389 }
1390 }
1391 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001392
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001393 if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.state == VolumeInfo.STATE_EJECTING) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001394 // TODO: this should eventually be handled by new ObbVolume state changes
1395 /*
1396 * Some OBBs might have been unmounted when this volume was
1397 * unmounted, so send a message to the handler to let it know to
1398 * remove those from the list of mounted OBBS.
1399 */
1400 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
1401 OBB_FLUSH_MOUNT_STATE, vol.path));
1402 }
San Mehat4270e1e2010-01-29 05:32:19 -08001403 }
1404
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001405 private void onMoveStatusLocked(int status) {
1406 if (mMoveCallback == null) {
1407 Slog.w(TAG, "Odd, status but no move requested");
1408 return;
1409 }
1410
1411 // TODO: estimate remaining time
1412 try {
Jeff Sharkey50a05452015-04-29 11:24:52 -07001413 mMoveCallback.onStatusChanged(-1, status, -1);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001414 } catch (RemoteException ignored) {
1415 }
1416
1417 // We've finished copying and we're about to clean up old data, so
1418 // remember that move was successful if we get rebooted
1419 if (status == MOVE_STATUS_COPY_FINISHED) {
1420 Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
1421
1422 mPrimaryStorageUuid = mMoveTargetUuid;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001423 writeSettingsLocked();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001424 }
1425
1426 if (PackageManager.isMoveStatusFinished(status)) {
1427 Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status);
1428
1429 mMoveCallback = null;
1430 mMoveTargetUuid = null;
1431 }
1432 }
1433
Jeff Sharkey48877892015-03-18 11:27:19 -07001434 private void enforcePermission(String perm) {
1435 mContext.enforceCallingOrSelfPermission(perm, perm);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001436 }
1437
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001438 /**
1439 * Decide if volume is mountable per device policies.
1440 */
1441 private boolean isMountDisallowed(VolumeInfo vol) {
Philip P. Moltmann5201f1e2016-09-30 14:58:27 -07001442 UserManager userManager = mContext.getSystemService(UserManager.class);
1443
1444 boolean isUsbRestricted = false;
1445 if (vol.disk != null && vol.disk.isUsb()) {
1446 isUsbRestricted = userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER,
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001447 Binder.getCallingUserHandle());
Emily Bernier92aa5a22014-07-07 10:11:48 -04001448 }
Philip P. Moltmann5201f1e2016-09-30 14:58:27 -07001449
1450 boolean isTypeRestricted = false;
1451 if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
1452 isTypeRestricted = userManager
1453 .hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
1454 Binder.getCallingUserHandle());
1455 }
1456
1457 return isUsbRestricted || isTypeRestricted;
Emily Bernier92aa5a22014-07-07 10:11:48 -04001458 }
1459
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001460 private void enforceAdminUser() {
1461 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1462 final int callingUserId = UserHandle.getCallingUserId();
1463 boolean isAdmin;
1464 long token = Binder.clearCallingIdentity();
1465 try {
1466 isAdmin = um.getUserInfo(callingUserId).isAdmin();
1467 } finally {
1468 Binder.restoreCallingIdentity(token);
1469 }
1470 if (!isAdmin) {
1471 throw new SecurityException("Only admin users can adopt sd cards");
1472 }
1473 }
1474
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001475 /**
San Mehat207e5382010-02-04 20:46:54 -08001476 * Constructs a new MountService instance
1477 *
1478 * @param context Binder context for this service
1479 */
1480 public MountService(Context context) {
Christopher Tated417d622013-08-19 16:14:25 -07001481 sSelf = this;
1482
San Mehat207e5382010-02-04 20:46:54 -08001483 mContext = context;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001484 mCallbacks = new Callbacks(FgThread.get().getLooper());
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001485 mLockPatternUtils = new LockPatternUtils(mContext);
San Mehat207e5382010-02-04 20:46:54 -08001486
San Mehat207e5382010-02-04 20:46:54 -08001487 // XXX: This will go away soon in favor of IMountServiceObserver
1488 mPms = (PackageManagerService) ServiceManager.getService("package");
1489
Dianne Hackbornefa92b22013-05-03 14:11:43 -07001490 HandlerThread hthread = new HandlerThread(TAG);
1491 hthread.start();
1492 mHandler = new MountServiceHandler(hthread.getLooper());
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001493
Kenny Roota02b8b02010-08-05 16:14:17 -07001494 // Add OBB Action Handler to MountService thread.
Dianne Hackborn8d044e82013-04-30 17:24:15 -07001495 mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
Kenny Roota02b8b02010-08-05 16:14:17 -07001496
Christopher Tate7265abe2014-11-21 13:54:45 -08001497 // Initialize the last-fstrim tracking if necessary
1498 File dataDir = Environment.getDataDirectory();
1499 File systemDir = new File(dataDir, "system");
1500 mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
1501 if (!mLastMaintenanceFile.exists()) {
1502 // Not setting mLastMaintenance here means that we will force an
1503 // fstrim during reboot following the OTA that installs this code.
1504 try {
1505 (new FileOutputStream(mLastMaintenanceFile)).close();
1506 } catch (IOException e) {
1507 Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
1508 }
1509 } else {
1510 mLastMaintenance = mLastMaintenanceFile.lastModified();
1511 }
1512
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001513 mSettingsFile = new AtomicFile(
Jeff Sharkey8212ae02016-02-10 14:46:43 -07001514 new File(Environment.getDataSystemDirectory(), "storage.xml"));
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001515
1516 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001517 readSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001518 }
1519
Svet Ganov6ee871e2015-07-10 14:29:33 -07001520 LocalServices.addService(MountServiceInternal.class, mMountServiceInternal);
1521
Marco Nelissenc34ebce2010-02-18 13:39:41 -08001522 /*
Kenny Root305bcbf2010-09-03 07:56:38 -07001523 * Create the connection to vold with a maximum queue of twice the
1524 * amount of containers we'd ever expect to have. This keeps an
1525 * "asec list" from blocking a thread repeatedly.
1526 */
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001527
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001528 mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
1529 null);
Jeff Sharkey48877892015-03-18 11:27:19 -07001530 mConnector.setDebug(true);
Jeff Sharkey8948c012015-11-03 12:33:54 -08001531 mConnector.setWarnIfHeld(mLock);
Jeff Sharkeycd575992016-03-29 14:12:49 -06001532 mConnectorThread = new Thread(mConnector, VOLD_TAG);
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07001533
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001534 // Reuse parameters from first connector since they are tested and safe
1535 mCryptConnector = new NativeDaemonConnector(this, "cryptd",
1536 MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
1537 mCryptConnector.setDebug(true);
Jeff Sharkeycd575992016-03-29 14:12:49 -06001538 mCryptConnectorThread = new Thread(mCryptConnector, CRYPTD_TAG);
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001539
Jeff Sharkeybcd262d2015-06-10 09:41:17 -07001540 final IntentFilter userFilter = new IntentFilter();
1541 userFilter.addAction(Intent.ACTION_USER_ADDED);
1542 userFilter.addAction(Intent.ACTION_USER_REMOVED);
1543 mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
1544
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001545 synchronized (mLock) {
1546 addInternalVolumeLocked();
1547 }
Amith Yamasania7892482015-08-07 11:09:05 -07001548
Kenny Root07714d42011-08-17 17:49:28 -07001549 // Add ourself to the Watchdog monitors if enabled.
1550 if (WATCHDOG_ENABLE) {
1551 Watchdog.getInstance().addMonitor(this);
1552 }
San Mehat207e5382010-02-04 20:46:54 -08001553 }
1554
Jeff Sharkeycd575992016-03-29 14:12:49 -06001555 private void start() {
1556 mConnectorThread.start();
1557 mCryptConnectorThread.start();
1558 }
1559
Jeff Sharkey56e62932015-03-21 20:41:00 -07001560 private void systemReady() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001561 mSystemReady = true;
1562 mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
1563 }
1564
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001565 private void bootCompleted() {
1566 mBootCompleted = true;
1567 }
1568
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001569 private String getDefaultPrimaryStorageUuid() {
1570 if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) {
1571 return StorageManager.UUID_PRIMARY_PHYSICAL;
1572 } else {
1573 return StorageManager.UUID_PRIVATE_INTERNAL;
1574 }
1575 }
1576
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001577 private void readSettingsLocked() {
1578 mRecords.clear();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001579 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001580 mForceAdoptable = false;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001581
1582 FileInputStream fis = null;
1583 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001584 fis = mSettingsFile.openRead();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001585 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001586 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001587
1588 int type;
1589 while ((type = in.next()) != END_DOCUMENT) {
1590 if (type == START_TAG) {
1591 final String tag = in.getName();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001592 if (TAG_VOLUMES.equals(tag)) {
1593 final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001594 final boolean primaryPhysical = SystemProperties.getBoolean(
1595 StorageManager.PROP_PRIMARY_PHYSICAL, false);
1596 final boolean validAttr = (version >= VERSION_FIX_PRIMARY)
1597 || (version >= VERSION_ADD_PRIMARY && !primaryPhysical);
1598 if (validAttr) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001599 mPrimaryStorageUuid = readStringAttribute(in,
1600 ATTR_PRIMARY_STORAGE_UUID);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001601 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001602 mForceAdoptable = readBooleanAttribute(in, ATTR_FORCE_ADOPTABLE, false);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001603
1604 } else if (TAG_VOLUME.equals(tag)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001605 final VolumeRecord rec = readVolumeRecord(in);
1606 mRecords.put(rec.fsUuid, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001607 }
1608 }
1609 }
1610 } catch (FileNotFoundException e) {
1611 // Missing metadata is okay, probably first boot
1612 } catch (IOException e) {
1613 Slog.wtf(TAG, "Failed reading metadata", e);
1614 } catch (XmlPullParserException e) {
1615 Slog.wtf(TAG, "Failed reading metadata", e);
1616 } finally {
1617 IoUtils.closeQuietly(fis);
1618 }
1619 }
1620
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001621 private void writeSettingsLocked() {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001622 FileOutputStream fos = null;
1623 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001624 fos = mSettingsFile.startWrite();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001625
1626 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001627 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001628 out.startDocument(null, true);
1629 out.startTag(null, TAG_VOLUMES);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001630 writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001631 writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001632 writeBooleanAttribute(out, ATTR_FORCE_ADOPTABLE, mForceAdoptable);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001633 final int size = mRecords.size();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001634 for (int i = 0; i < size; i++) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001635 final VolumeRecord rec = mRecords.valueAt(i);
1636 writeVolumeRecord(out, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001637 }
1638 out.endTag(null, TAG_VOLUMES);
1639 out.endDocument();
1640
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001641 mSettingsFile.finishWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001642 } catch (IOException e) {
1643 if (fos != null) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001644 mSettingsFile.failWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001645 }
1646 }
1647 }
1648
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001649 public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
1650 final int type = readIntAttribute(in, ATTR_TYPE);
1651 final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
1652 final VolumeRecord meta = new VolumeRecord(type, fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001653 meta.partGuid = readStringAttribute(in, ATTR_PART_GUID);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001654 meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
1655 meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001656 meta.createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
1657 meta.lastTrimMillis = readLongAttribute(in, ATTR_LAST_TRIM_MILLIS);
1658 meta.lastBenchMillis = readLongAttribute(in, ATTR_LAST_BENCH_MILLIS);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001659 return meta;
1660 }
1661
1662 public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
1663 out.startTag(null, TAG_VOLUME);
1664 writeIntAttribute(out, ATTR_TYPE, rec.type);
1665 writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001666 writeStringAttribute(out, ATTR_PART_GUID, rec.partGuid);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001667 writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
1668 writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001669 writeLongAttribute(out, ATTR_CREATED_MILLIS, rec.createdMillis);
1670 writeLongAttribute(out, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
1671 writeLongAttribute(out, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001672 out.endTag(null, TAG_VOLUME);
1673 }
1674
San Mehat207e5382010-02-04 20:46:54 -08001675 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001676 * Exposed API calls below here
1677 */
1678
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001679 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001680 public void registerListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001681 mCallbacks.register(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001682 }
1683
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001684 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001685 public void unregisterListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001686 mCallbacks.unregister(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001687 }
1688
Jeff Sharkey48877892015-03-18 11:27:19 -07001689 @Override
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -08001690 public void shutdown(final IMountShutdownObserver observer) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001691 enforcePermission(android.Manifest.permission.SHUTDOWN);
San Mehat4270e1e2010-01-29 05:32:19 -08001692
San Mehata5078592010-03-25 09:36:54 -07001693 Slog.i(TAG, "Shutting down");
Jeff Sharkey48877892015-03-18 11:27:19 -07001694 mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001695 }
1696
Jeff Sharkey48877892015-03-18 11:27:19 -07001697 @Override
San Mehatb1043402010-02-05 08:26:50 -08001698 public boolean isUsbMassStorageConnected() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001699 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001700 }
1701
Jeff Sharkey48877892015-03-18 11:27:19 -07001702 @Override
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -08001703 public void setUsbMassStorageEnabled(boolean enable) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001704 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001705 }
1706
Jeff Sharkey48877892015-03-18 11:27:19 -07001707 @Override
San Mehatb1043402010-02-05 08:26:50 -08001708 public boolean isUsbMassStorageEnabled() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001709 throw new UnsupportedOperationException();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001710 }
Jason parks9ed98bc2011-01-17 09:58:35 -06001711
Jeff Sharkey48877892015-03-18 11:27:19 -07001712 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001713 public String getVolumeState(String mountPoint) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001714 throw new UnsupportedOperationException();
San Mehat7fd0fee2009-12-17 07:12:23 -08001715 }
1716
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001717 @Override
Kenny Roote1ff2142010-10-12 11:20:01 -07001718 public boolean isExternalStorageEmulated() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001719 throw new UnsupportedOperationException();
Kenny Roote1ff2142010-10-12 11:20:01 -07001720 }
1721
Jeff Sharkey48877892015-03-18 11:27:19 -07001722 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001723 public int mountVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001724 mount(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001725 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726 }
1727
Jeff Sharkey48877892015-03-18 11:27:19 -07001728 @Override
Ben Komalo13c71972011-09-07 16:35:56 -07001729 public void unmountVolume(String path, boolean force, boolean removeEncryption) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001730 unmount(findVolumeIdForPathOrThrow(path));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731 }
1732
Jeff Sharkey48877892015-03-18 11:27:19 -07001733 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001734 public int formatVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001735 format(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001736 return 0;
1737 }
1738
1739 @Override
1740 public void mount(String volId) {
1741 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1742 waitForReady();
1743
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001744 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001745 if (isMountDisallowed(vol)) {
1746 throw new SecurityException("Mounting " + volId + " restricted by policy");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001747 }
1748 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001749 mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001750 } catch (NativeDaemonConnectorException e) {
1751 throw e.rethrowAsParcelableException();
1752 }
1753 }
1754
1755 @Override
1756 public void unmount(String volId) {
1757 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1758 waitForReady();
1759
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001760 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001761
1762 // TODO: expand PMS to know about multiple volumes
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001763 if (vol.isPrimaryPhysical()) {
1764 final long ident = Binder.clearCallingIdentity();
1765 try {
1766 synchronized (mUnmountLock) {
1767 mUnmountSignal = new CountDownLatch(1);
1768 mPms.updateExternalMediaStatus(false, true);
1769 waitForLatch(mUnmountSignal, "mUnmountSignal");
1770 mUnmountSignal = null;
1771 }
1772 } finally {
1773 Binder.restoreCallingIdentity(ident);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001774 }
1775 }
1776
1777 try {
1778 mConnector.execute("volume", "unmount", vol.id);
1779 } catch (NativeDaemonConnectorException e) {
1780 throw e.rethrowAsParcelableException();
1781 }
1782 }
1783
1784 @Override
1785 public void format(String volId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001786 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -08001787 waitForReady();
San Mehat5b77dab2010-01-26 13:28:50 -08001788
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001789 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001790 try {
Jeff Sharkey4e83cc92015-05-27 14:38:39 -07001791 mConnector.execute("volume", "format", vol.id, "auto");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001792 } catch (NativeDaemonConnectorException e) {
1793 throw e.rethrowAsParcelableException();
Jeff Sharkey48877892015-03-18 11:27:19 -07001794 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001795 }
1796
1797 @Override
Jeff Sharkey9756d752015-05-14 21:07:42 -07001798 public long benchmark(String volId) {
1799 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1800 waitForReady();
1801
1802 try {
Jeff Sharkey14cbe522015-07-08 14:06:37 -07001803 // TODO: make benchmark async so we don't block other commands
1804 final NativeDaemonEvent res = mConnector.execute(3 * DateUtils.MINUTE_IN_MILLIS,
1805 "volume", "benchmark", volId);
Jeff Sharkey9756d752015-05-14 21:07:42 -07001806 return Long.parseLong(res.getMessage());
Todd Kennedy8101ee62015-06-23 13:35:28 -07001807 } catch (NativeDaemonTimeoutException e) {
1808 return Long.MAX_VALUE;
Jeff Sharkey9756d752015-05-14 21:07:42 -07001809 } catch (NativeDaemonConnectorException e) {
1810 throw e.rethrowAsParcelableException();
1811 }
1812 }
1813
1814 @Override
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001815 public void partitionPublic(String diskId) {
1816 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1817 waitForReady();
1818
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001819 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001820 try {
1821 mConnector.execute("volume", "partition", diskId, "public");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001822 waitForLatch(latch, "partitionPublic", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001823 } catch (NativeDaemonConnectorException e) {
1824 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001825 } catch (TimeoutException e) {
1826 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001827 }
1828 }
1829
1830 @Override
1831 public void partitionPrivate(String diskId) {
1832 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001833 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001834 waitForReady();
1835
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001836 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001837 try {
1838 mConnector.execute("volume", "partition", diskId, "private");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001839 waitForLatch(latch, "partitionPrivate", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001840 } catch (NativeDaemonConnectorException e) {
1841 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001842 } catch (TimeoutException e) {
1843 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001844 }
1845 }
1846
1847 @Override
1848 public void partitionMixed(String diskId, int ratio) {
1849 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001850 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001851 waitForReady();
1852
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001853 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001854 try {
1855 mConnector.execute("volume", "partition", diskId, "mixed", ratio);
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001856 waitForLatch(latch, "partitionMixed", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001857 } catch (NativeDaemonConnectorException e) {
1858 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001859 } catch (TimeoutException e) {
1860 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001861 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001862 }
1863
Jeff Sharkey48877892015-03-18 11:27:19 -07001864 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001865 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001866 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1867 waitForReady();
1868
Jeff Sharkey50a05452015-04-29 11:24:52 -07001869 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001870 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001871 final VolumeRecord rec = mRecords.get(fsUuid);
1872 rec.nickname = nickname;
Jeff Sharkey50a05452015-04-29 11:24:52 -07001873 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001874 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001875 }
1876 }
1877
1878 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001879 public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001880 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1881 waitForReady();
1882
Jeff Sharkey50a05452015-04-29 11:24:52 -07001883 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001884 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001885 final VolumeRecord rec = mRecords.get(fsUuid);
1886 rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001887 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001888 writeSettingsLocked();
1889 }
1890 }
1891
1892 @Override
1893 public void forgetVolume(String fsUuid) {
1894 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1895 waitForReady();
1896
Jeff Sharkey50a05452015-04-29 11:24:52 -07001897 Preconditions.checkNotNull(fsUuid);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001898
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001899 synchronized (mLock) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001900 final VolumeRecord rec = mRecords.remove(fsUuid);
1901 if (rec != null && !TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001902 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001903 }
1904 mCallbacks.notifyVolumeForgotten(fsUuid);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001905
1906 // If this had been primary storage, revert back to internal and
1907 // reset vold so we bind into new volume into place.
1908 if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001909 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001910 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001911 }
1912
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001913 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001914 }
1915 }
1916
Jeff Sharkey7d2af542015-05-12 15:27:15 -07001917 @Override
1918 public void forgetAllVolumes() {
1919 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1920 waitForReady();
1921
Jeff Sharkey50a05452015-04-29 11:24:52 -07001922 synchronized (mLock) {
1923 for (int i = 0; i < mRecords.size(); i++) {
1924 final String fsUuid = mRecords.keyAt(i);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001925 final VolumeRecord rec = mRecords.valueAt(i);
1926 if (!TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001927 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001928 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001929 mCallbacks.notifyVolumeForgotten(fsUuid);
1930 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001931 mRecords.clear();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001932
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001933 if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)) {
1934 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
1935 }
1936
1937 writeSettingsLocked();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001938 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001939 }
1940 }
1941
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001942 private void forgetPartition(String partGuid) {
1943 try {
1944 mConnector.execute("volume", "forget_partition", partGuid);
1945 } catch (NativeDaemonConnectorException e) {
1946 Slog.w(TAG, "Failed to forget key for " + partGuid + ": " + e);
1947 }
1948 }
1949
Svet Ganov6ee871e2015-07-10 14:29:33 -07001950 private void remountUidExternalStorage(int uid, int mode) {
Jeff Sharkey9527b222015-06-24 15:24:48 -07001951 waitForReady();
1952
Svet Ganov6ee871e2015-07-10 14:29:33 -07001953 String modeName = "none";
1954 switch (mode) {
1955 case Zygote.MOUNT_EXTERNAL_DEFAULT: {
1956 modeName = "default";
1957 } break;
1958
1959 case Zygote.MOUNT_EXTERNAL_READ: {
1960 modeName = "read";
1961 } break;
1962
1963 case Zygote.MOUNT_EXTERNAL_WRITE: {
1964 modeName = "write";
1965 } break;
Jeff Sharkey9527b222015-06-24 15:24:48 -07001966 }
1967
1968 try {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001969 mConnector.execute("volume", "remount_uid", uid, modeName);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001970 } catch (NativeDaemonConnectorException e) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001971 Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001972 }
1973 }
1974
1975 @Override
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001976 public void setDebugFlags(int flags, int mask) {
1977 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1978 waitForReady();
1979
Jeff Sharkeyba512352015-11-12 20:17:45 -08001980 if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
Paul Lawrence20be5d62016-02-26 13:51:17 -08001981 if (StorageManager.isFileEncryptedNativeOnly()) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001982 throw new IllegalStateException(
1983 "Emulation not available on device with native FBE");
1984 }
Jeff Sharkey5a785162016-03-21 13:02:06 -06001985 if (mLockPatternUtils.isCredentialRequiredToDecrypt(false)) {
1986 throw new IllegalStateException(
1987 "Emulation requires disabling 'Secure start-up' in Settings > Security");
1988 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001989
Jeff Sharkey1176e512016-02-29 17:01:26 -07001990 final long token = Binder.clearCallingIdentity();
1991 try {
1992 final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
1993 SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001994
Jeff Sharkey1176e512016-02-29 17:01:26 -07001995 // Perform hard reboot to kick policy into place
1996 mContext.getSystemService(PowerManager.class).reboot(null);
1997 } finally {
1998 Binder.restoreCallingIdentity(token);
1999 }
Jeff Sharkeyba512352015-11-12 20:17:45 -08002000 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002001
Jeff Sharkeyba512352015-11-12 20:17:45 -08002002 if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
Jeff Sharkey6ed74182016-08-23 13:53:53 -06002003 if (StorageManager.isFileEncryptedNativeOnly()) {
2004 throw new IllegalStateException(
2005 "Adoptable storage not available on device with native FBE");
2006 }
2007
Jeff Sharkeyba512352015-11-12 20:17:45 -08002008 synchronized (mLock) {
2009 mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
2010
2011 writeSettingsLocked();
2012 mHandler.obtainMessage(H_RESET).sendToTarget();
2013 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002014 }
Jeff Sharkey33dd1562016-04-07 11:05:33 -06002015
2016 if ((mask & (StorageManager.DEBUG_SDCARDFS_FORCE_ON
2017 | StorageManager.DEBUG_SDCARDFS_FORCE_OFF)) != 0) {
2018 final String value;
2019 if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_ON) != 0) {
2020 value = "force_on";
2021 } else if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_OFF) != 0) {
2022 value = "force_off";
2023 } else {
2024 value = "";
2025 }
2026
2027 final long token = Binder.clearCallingIdentity();
2028 try {
2029 SystemProperties.set(StorageManager.PROP_SDCARDFS, value);
2030
2031 // Reset storage to kick new setting into place
2032 mHandler.obtainMessage(H_RESET).sendToTarget();
2033 } finally {
2034 Binder.restoreCallingIdentity(token);
2035 }
2036 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002037 }
2038
2039 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002040 public String getPrimaryStorageUuid() {
2041 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2042 waitForReady();
2043
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002044 synchronized (mLock) {
2045 return mPrimaryStorageUuid;
2046 }
2047 }
2048
2049 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002050 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
2051 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2052 waitForReady();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002053
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002054 final VolumeInfo from;
2055 final VolumeInfo to;
2056
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002057 synchronized (mLock) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002058 if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) {
2059 throw new IllegalArgumentException("Primary storage already at " + volumeUuid);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002060 }
2061
2062 if (mMoveCallback != null) {
2063 throw new IllegalStateException("Move already in progress");
2064 }
2065 mMoveCallback = callback;
2066 mMoveTargetUuid = volumeUuid;
2067
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002068 // When moving to/from primary physical volume, we probably just nuked
2069 // the current storage location, so we have nothing to move.
2070 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
2071 || Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
2072 Slog.d(TAG, "Skipping move to/from primary physical");
2073 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
2074 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08002075 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002076 return;
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002077
2078 } else {
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002079 from = findStorageForUuid(mPrimaryStorageUuid);
2080 to = findStorageForUuid(volumeUuid);
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07002081
2082 if (from == null) {
2083 Slog.w(TAG, "Failing move due to missing from volume " + mPrimaryStorageUuid);
2084 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2085 return;
2086 } else if (to == null) {
2087 Slog.w(TAG, "Failing move due to missing to volume " + volumeUuid);
2088 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2089 return;
2090 }
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002091 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002092 }
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002093
2094 try {
2095 mConnector.execute("volume", "move_storage", from.id, to.id);
2096 } catch (NativeDaemonConnectorException e) {
2097 throw e.rethrowAsParcelableException();
2098 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002099 }
2100
2101 @Override
Mike Lockwoodecedfdc2011-06-08 15:11:59 -07002102 public int[] getStorageUsers(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002103 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehatc1b4ce92010-02-16 17:13:03 -08002104 waitForReady();
2105 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002106 final String[] r = NativeDaemonEvent.filterMessageList(
2107 mConnector.executeForList("storage", "users", path),
2108 VoldResponseCode.StorageUsersListResult);
2109
San Mehatc1b4ce92010-02-16 17:13:03 -08002110 // FMT: <pid> <process name>
2111 int[] data = new int[r.length];
2112 for (int i = 0; i < r.length; i++) {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002113 String[] tok = r[i].split(" ");
San Mehatc1b4ce92010-02-16 17:13:03 -08002114 try {
2115 data[i] = Integer.parseInt(tok[0]);
2116 } catch (NumberFormatException nfe) {
San Mehata5078592010-03-25 09:36:54 -07002117 Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
San Mehatc1b4ce92010-02-16 17:13:03 -08002118 return new int[0];
2119 }
2120 }
2121 return data;
2122 } catch (NativeDaemonConnectorException e) {
San Mehata5078592010-03-25 09:36:54 -07002123 Slog.e(TAG, "Failed to retrieve storage users list", e);
San Mehatc1b4ce92010-02-16 17:13:03 -08002124 return new int[0];
2125 }
2126 }
2127
San Mehatb1043402010-02-05 08:26:50 -08002128 private void warnOnNotMounted() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002129 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002130 for (int i = 0; i < mVolumes.size(); i++) {
2131 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07002132 if (vol.isPrimary() && vol.isMountedWritable()) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002133 // Cool beans, we have a mounted primary volume
2134 return;
2135 }
Jeff Sharkey32ee8312012-09-30 13:21:31 -07002136 }
San Mehatb1043402010-02-05 08:26:50 -08002137 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002138
2139 Slog.w(TAG, "No primary storage mounted!");
San Mehatb1043402010-02-05 08:26:50 -08002140 }
2141
San Mehat4270e1e2010-01-29 05:32:19 -08002142 public String[] getSecureContainerList() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002143 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002144 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002145 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002146
San Mehat4270e1e2010-01-29 05:32:19 -08002147 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002148 return NativeDaemonEvent.filterMessageList(
2149 mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
San Mehat4270e1e2010-01-29 05:32:19 -08002150 } catch (NativeDaemonConnectorException e) {
2151 return new String[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 }
2153 }
San Mehat36972292010-01-06 11:06:32 -08002154
Kenny Root6dceb882012-04-12 14:23:49 -07002155 public int createSecureContainer(String id, int sizeMb, String fstype, String key,
2156 int ownerUid, boolean external) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002157 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehat207e5382010-02-04 20:46:54 -08002158 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002159 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002160
San Mehatb1043402010-02-05 08:26:50 -08002161 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002162 try {
Jeff Sharkey56cd6462013-06-07 15:09:15 -07002163 mConnector.execute("asec", "create", id, sizeMb, fstype, new SensitiveArg(key),
2164 ownerUid, external ? "1" : "0");
San Mehat4270e1e2010-01-29 05:32:19 -08002165 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002166 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002167 }
San Mehata181b212010-02-11 06:50:20 -08002168
2169 if (rc == StorageResultCode.OperationSucceeded) {
2170 synchronized (mAsecMountSet) {
2171 mAsecMountSet.add(id);
2172 }
2173 }
San Mehat4270e1e2010-01-29 05:32:19 -08002174 return rc;
San Mehat36972292010-01-06 11:06:32 -08002175 }
2176
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002177 @Override
2178 public int resizeSecureContainer(String id, int sizeMb, String key) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002179 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002180 waitForReady();
2181 warnOnNotMounted();
2182
2183 int rc = StorageResultCode.OperationSucceeded;
2184 try {
2185 mConnector.execute("asec", "resize", id, sizeMb, new SensitiveArg(key));
2186 } catch (NativeDaemonConnectorException e) {
2187 rc = StorageResultCode.OperationFailedInternalError;
2188 }
2189 return rc;
2190 }
2191
San Mehat4270e1e2010-01-29 05:32:19 -08002192 public int finalizeSecureContainer(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002193 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehatb1043402010-02-05 08:26:50 -08002194 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002195
San Mehatb1043402010-02-05 08:26:50 -08002196 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002197 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002198 mConnector.execute("asec", "finalize", id);
San Mehata181b212010-02-11 06:50:20 -08002199 /*
2200 * Finalization does a remount, so no need
2201 * to update mAsecMountSet
2202 */
San Mehat4270e1e2010-01-29 05:32:19 -08002203 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002204 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002205 }
San Mehat4270e1e2010-01-29 05:32:19 -08002206 return rc;
San Mehat36972292010-01-06 11:06:32 -08002207 }
2208
Kenny Root6dceb882012-04-12 14:23:49 -07002209 public int fixPermissionsSecureContainer(String id, int gid, String filename) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002210 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Kenny Root6dceb882012-04-12 14:23:49 -07002211 warnOnNotMounted();
2212
2213 int rc = StorageResultCode.OperationSucceeded;
2214 try {
2215 mConnector.execute("asec", "fixperms", id, gid, filename);
2216 /*
2217 * Fix permissions does a remount, so no need to update
2218 * mAsecMountSet
2219 */
2220 } catch (NativeDaemonConnectorException e) {
2221 rc = StorageResultCode.OperationFailedInternalError;
2222 }
2223 return rc;
2224 }
2225
San Mehatd9709982010-02-18 11:43:03 -08002226 public int destroySecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002227 enforcePermission(android.Manifest.permission.ASEC_DESTROY);
San Mehat207e5382010-02-04 20:46:54 -08002228 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002229 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002230
Kenny Rootaa485402010-09-14 14:49:41 -07002231 /*
2232 * Force a GC to make sure AssetManagers in other threads of the
2233 * system_server are cleaned up. We have to do this since AssetManager
2234 * instances are kept as a WeakReference and it's possible we have files
2235 * open on the external storage.
2236 */
2237 Runtime.getRuntime().gc();
2238
San Mehatb1043402010-02-05 08:26:50 -08002239 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002240 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002241 final Command cmd = new Command("asec", "destroy", id);
2242 if (force) {
2243 cmd.appendArg("force");
2244 }
2245 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002246 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002247 int code = e.getCode();
2248 if (code == VoldResponseCode.OpFailedStorageBusy) {
2249 rc = StorageResultCode.OperationFailedStorageBusy;
2250 } else {
2251 rc = StorageResultCode.OperationFailedInternalError;
2252 }
San Mehat02735bc2010-01-26 15:18:08 -08002253 }
San Mehata181b212010-02-11 06:50:20 -08002254
2255 if (rc == StorageResultCode.OperationSucceeded) {
2256 synchronized (mAsecMountSet) {
2257 if (mAsecMountSet.contains(id)) {
2258 mAsecMountSet.remove(id);
2259 }
2260 }
2261 }
2262
San Mehat4270e1e2010-01-29 05:32:19 -08002263 return rc;
San Mehat36972292010-01-06 11:06:32 -08002264 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002265
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002266 public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002267 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002268 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002269 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002270
San Mehata181b212010-02-11 06:50:20 -08002271 synchronized (mAsecMountSet) {
2272 if (mAsecMountSet.contains(id)) {
2273 return StorageResultCode.OperationFailedStorageMounted;
2274 }
2275 }
2276
San Mehatb1043402010-02-05 08:26:50 -08002277 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002278 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002279 mConnector.execute("asec", "mount", id, new SensitiveArg(key), ownerUid,
2280 readOnly ? "ro" : "rw");
San Mehat4270e1e2010-01-29 05:32:19 -08002281 } catch (NativeDaemonConnectorException e) {
Kenny Rootf0304622010-03-19 19:20:42 -07002282 int code = e.getCode();
2283 if (code != VoldResponseCode.OpFailedStorageBusy) {
2284 rc = StorageResultCode.OperationFailedInternalError;
2285 }
San Mehat02735bc2010-01-26 15:18:08 -08002286 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002287
2288 if (rc == StorageResultCode.OperationSucceeded) {
2289 synchronized (mAsecMountSet) {
2290 mAsecMountSet.add(id);
2291 }
2292 }
San Mehat4270e1e2010-01-29 05:32:19 -08002293 return rc;
San Mehat36972292010-01-06 11:06:32 -08002294 }
2295
San Mehatd9709982010-02-18 11:43:03 -08002296 public int unmountSecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002297 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002298 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002299 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002300
San Mehat6cdd9c02010-02-09 14:45:20 -08002301 synchronized (mAsecMountSet) {
2302 if (!mAsecMountSet.contains(id)) {
San Mehata181b212010-02-11 06:50:20 -08002303 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehat6cdd9c02010-02-09 14:45:20 -08002304 }
2305 }
2306
Kenny Rootaa485402010-09-14 14:49:41 -07002307 /*
2308 * Force a GC to make sure AssetManagers in other threads of the
2309 * system_server are cleaned up. We have to do this since AssetManager
2310 * instances are kept as a WeakReference and it's possible we have files
2311 * open on the external storage.
2312 */
2313 Runtime.getRuntime().gc();
2314
San Mehatb1043402010-02-05 08:26:50 -08002315 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002316 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002317 final Command cmd = new Command("asec", "unmount", id);
2318 if (force) {
2319 cmd.appendArg("force");
2320 }
2321 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002322 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002323 int code = e.getCode();
2324 if (code == VoldResponseCode.OpFailedStorageBusy) {
2325 rc = StorageResultCode.OperationFailedStorageBusy;
2326 } else {
2327 rc = StorageResultCode.OperationFailedInternalError;
2328 }
San Mehat02735bc2010-01-26 15:18:08 -08002329 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002330
2331 if (rc == StorageResultCode.OperationSucceeded) {
2332 synchronized (mAsecMountSet) {
2333 mAsecMountSet.remove(id);
2334 }
2335 }
San Mehat4270e1e2010-01-29 05:32:19 -08002336 return rc;
San Mehat9dba7092010-01-18 06:47:41 -08002337 }
2338
San Mehat6cdd9c02010-02-09 14:45:20 -08002339 public boolean isSecureContainerMounted(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002340 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat6cdd9c02010-02-09 14:45:20 -08002341 waitForReady();
2342 warnOnNotMounted();
2343
2344 synchronized (mAsecMountSet) {
2345 return mAsecMountSet.contains(id);
2346 }
2347 }
2348
San Mehat4270e1e2010-01-29 05:32:19 -08002349 public int renameSecureContainer(String oldId, String newId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002350 enforcePermission(android.Manifest.permission.ASEC_RENAME);
San Mehat207e5382010-02-04 20:46:54 -08002351 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002352 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002353
San Mehata181b212010-02-11 06:50:20 -08002354 synchronized (mAsecMountSet) {
San Mehat85451ee2010-02-24 08:54:18 -08002355 /*
Jason parks9ed98bc2011-01-17 09:58:35 -06002356 * Because a mounted container has active internal state which cannot be
San Mehat85451ee2010-02-24 08:54:18 -08002357 * changed while active, we must ensure both ids are not currently mounted.
2358 */
2359 if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
San Mehata181b212010-02-11 06:50:20 -08002360 return StorageResultCode.OperationFailedStorageMounted;
2361 }
2362 }
2363
San Mehatb1043402010-02-05 08:26:50 -08002364 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002365 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002366 mConnector.execute("asec", "rename", oldId, newId);
San Mehat4270e1e2010-01-29 05:32:19 -08002367 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002368 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002369 }
San Mehata181b212010-02-11 06:50:20 -08002370
San Mehat4270e1e2010-01-29 05:32:19 -08002371 return rc;
San Mehat45f61042010-01-23 08:12:43 -08002372 }
2373
San Mehat4270e1e2010-01-29 05:32:19 -08002374 public String getSecureContainerPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002375 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002376 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002377 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002378
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002379 final NativeDaemonEvent event;
San Mehat2d66cef2010-03-23 11:12:52 -07002380 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002381 event = mConnector.execute("asec", "path", id);
2382 event.checkCode(VoldResponseCode.AsecPathResult);
2383 return event.getMessage();
San Mehat2d66cef2010-03-23 11:12:52 -07002384 } catch (NativeDaemonConnectorException e) {
2385 int code = e.getCode();
2386 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Fredrik Helmera20c8ef2011-02-09 16:16:10 +01002387 Slog.i(TAG, String.format("Container '%s' not found", id));
2388 return null;
San Mehat22dd86e2010-01-12 12:21:18 -08002389 } else {
San Mehat2d66cef2010-03-23 11:12:52 -07002390 throw new IllegalStateException(String.format("Unexpected response code %d", code));
San Mehat22dd86e2010-01-12 12:21:18 -08002391 }
2392 }
San Mehat22dd86e2010-01-12 12:21:18 -08002393 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002394
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002395 public String getSecureContainerFilesystemPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002396 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002397 waitForReady();
2398 warnOnNotMounted();
2399
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002400 final NativeDaemonEvent event;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002401 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002402 event = mConnector.execute("asec", "fspath", id);
2403 event.checkCode(VoldResponseCode.AsecPathResult);
2404 return event.getMessage();
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002405 } catch (NativeDaemonConnectorException e) {
2406 int code = e.getCode();
2407 if (code == VoldResponseCode.OpFailedStorageNotFound) {
2408 Slog.i(TAG, String.format("Container '%s' not found", id));
2409 return null;
2410 } else {
2411 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2412 }
2413 }
2414 }
2415
Jeff Sharkey48877892015-03-18 11:27:19 -07002416 @Override
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002417 public void finishMediaUpdate() {
Jeff Sharkey9527b222015-06-24 15:24:48 -07002418 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
Rubin Xucd7a0142015-04-17 23:45:27 +01002419 throw new SecurityException("no permission to call finishMediaUpdate()");
2420 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002421 if (mUnmountSignal != null) {
2422 mUnmountSignal.countDown();
2423 } else {
2424 Slog.w(TAG, "Odd, nobody asked to unmount?");
2425 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002426 }
Kenny Root02c87302010-07-01 08:10:18 -07002427
Kenny Roota02b8b02010-08-05 16:14:17 -07002428 private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
2429 if (callerUid == android.os.Process.SYSTEM_UID) {
2430 return true;
2431 }
2432
Kenny Root02c87302010-07-01 08:10:18 -07002433 if (packageName == null) {
2434 return false;
2435 }
2436
Jeff Sharkeycd654482016-01-08 17:42:11 -07002437 final int packageUid = mPms.getPackageUid(packageName,
2438 PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callerUid));
Kenny Root02c87302010-07-01 08:10:18 -07002439
2440 if (DEBUG_OBB) {
2441 Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
2442 packageUid + ", callerUid = " + callerUid);
2443 }
2444
2445 return callerUid == packageUid;
2446 }
2447
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002448 public String getMountedObbPath(String rawPath) {
2449 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002450
Kenny Root02c87302010-07-01 08:10:18 -07002451 waitForReady();
2452 warnOnNotMounted();
2453
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002454 final ObbState state;
Rubin Xucd7a0142015-04-17 23:45:27 +01002455 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002456 state = mObbPathToStateMap.get(rawPath);
2457 }
2458 if (state == null) {
2459 Slog.w(TAG, "Failed to find OBB mounted at " + rawPath);
2460 return null;
2461 }
2462
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002463 final NativeDaemonEvent event;
Kenny Root02c87302010-07-01 08:10:18 -07002464 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07002465 event = mConnector.execute("obb", "path", state.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002466 event.checkCode(VoldResponseCode.AsecPathResult);
2467 return event.getMessage();
Kenny Root02c87302010-07-01 08:10:18 -07002468 } catch (NativeDaemonConnectorException e) {
2469 int code = e.getCode();
2470 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Kenny Roota02b8b02010-08-05 16:14:17 -07002471 return null;
Kenny Root02c87302010-07-01 08:10:18 -07002472 } else {
2473 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2474 }
2475 }
2476 }
2477
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002478 @Override
2479 public boolean isObbMounted(String rawPath) {
2480 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002481 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002482 return mObbPathToStateMap.containsKey(rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002483 }
Kenny Root02c87302010-07-01 08:10:18 -07002484 }
2485
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002486 @Override
2487 public void mountObb(
2488 String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) {
2489 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2490 Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
2491 Preconditions.checkNotNull(token, "token cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002492
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002493 final int callingUid = Binder.getCallingUid();
2494 final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce);
2495 final ObbAction action = new MountObbAction(obbState, key, callingUid);
Kenny Roota02b8b02010-08-05 16:14:17 -07002496 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
2497
2498 if (DEBUG_OBB)
2499 Slog.i(TAG, "Send to OBB handler: " + action.toString());
Kenny Root02c87302010-07-01 08:10:18 -07002500 }
2501
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002502 @Override
2503 public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
2504 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2505
2506 final ObbState existingState;
Rubin Xucd7a0142015-04-17 23:45:27 +01002507 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002508 existingState = mObbPathToStateMap.get(rawPath);
Kenny Rootf1121dc2010-09-29 07:30:53 -07002509 }
2510
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002511 if (existingState != null) {
2512 // TODO: separate state object from request data
2513 final int callingUid = Binder.getCallingUid();
2514 final ObbState newState = new ObbState(
2515 rawPath, existingState.canonicalPath, callingUid, token, nonce);
2516 final ObbAction action = new UnmountObbAction(newState, force);
2517 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root02c87302010-07-01 08:10:18 -07002518
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002519 if (DEBUG_OBB)
2520 Slog.i(TAG, "Send to OBB handler: " + action.toString());
2521 } else {
2522 Slog.w(TAG, "Unknown OBB mount at " + rawPath);
2523 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002524 }
2525
Ben Komalo444eca22011-09-01 15:17:44 -07002526 @Override
2527 public int getEncryptionState() {
2528 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2529 "no permission to access the crypt keeper");
2530
2531 waitForReady();
2532
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002533 final NativeDaemonEvent event;
Ben Komalo444eca22011-09-01 15:17:44 -07002534 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002535 event = mCryptConnector.execute("cryptfs", "cryptocomplete");
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002536 return Integer.parseInt(event.getMessage());
Ben Komalo444eca22011-09-01 15:17:44 -07002537 } catch (NumberFormatException e) {
2538 // Bad result - unexpected.
2539 Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
2540 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2541 } catch (NativeDaemonConnectorException e) {
2542 // Something bad happened.
2543 Slog.w(TAG, "Error in communicating with cryptfs in validating");
2544 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2545 }
2546 }
2547
2548 @Override
Jason parks5af0b912010-11-29 09:05:25 -06002549 public int decryptStorage(String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002550 if (TextUtils.isEmpty(password)) {
2551 throw new IllegalArgumentException("password cannot be empty");
Jason parks5af0b912010-11-29 09:05:25 -06002552 }
2553
Jason parks8888c592011-01-20 22:46:41 -06002554 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2555 "no permission to access the crypt keeper");
Jason parks5af0b912010-11-29 09:05:25 -06002556
2557 waitForReady();
2558
2559 if (DEBUG_EVENTS) {
2560 Slog.i(TAG, "decrypting storage...");
2561 }
2562
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002563 final NativeDaemonEvent event;
Jason parks5af0b912010-11-29 09:05:25 -06002564 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002565 event = mCryptConnector.execute("cryptfs", "checkpw", new SensitiveArg(password));
Jason parks9ed98bc2011-01-17 09:58:35 -06002566
Fredrik Roubertda6aedf2011-12-20 17:34:43 +01002567 final int code = Integer.parseInt(event.getMessage());
Jason parks9ed98bc2011-01-17 09:58:35 -06002568 if (code == 0) {
2569 // Decrypt was successful. Post a delayed message before restarting in order
2570 // to let the UI to clear itself
2571 mHandler.postDelayed(new Runnable() {
2572 public void run() {
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002573 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002574 mCryptConnector.execute("cryptfs", "restart");
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002575 } catch (NativeDaemonConnectorException e) {
2576 Slog.e(TAG, "problem executing in background", e);
2577 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002578 }
Jason parksf7b3cd42011-01-27 09:28:25 -06002579 }, 1000); // 1 second
Jason parks9ed98bc2011-01-17 09:58:35 -06002580 }
2581
2582 return code;
Jason parks5af0b912010-11-29 09:05:25 -06002583 } catch (NativeDaemonConnectorException e) {
2584 // Decryption failed
2585 return e.getCode();
2586 }
Jason parks5af0b912010-11-29 09:05:25 -06002587 }
2588
Paul Lawrence46791e72014-04-03 09:10:26 -07002589 public int encryptStorage(int type, String password) {
2590 if (TextUtils.isEmpty(password) && type != StorageManager.CRYPT_TYPE_DEFAULT) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002591 throw new IllegalArgumentException("password cannot be empty");
Jason parks56aa5322011-01-07 09:01:15 -06002592 }
2593
Jason parks8888c592011-01-20 22:46:41 -06002594 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2595 "no permission to access the crypt keeper");
Jason parks56aa5322011-01-07 09:01:15 -06002596
2597 waitForReady();
2598
2599 if (DEBUG_EVENTS) {
Jason parks8888c592011-01-20 22:46:41 -06002600 Slog.i(TAG, "encrypting storage...");
Jason parks56aa5322011-01-07 09:01:15 -06002601 }
2602
2603 try {
Paul Lawrence5096d9e2015-09-09 13:05:45 -07002604 if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
2605 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2606 CRYPTO_TYPES[type]);
2607 } else {
2608 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2609 CRYPTO_TYPES[type], new SensitiveArg(password));
2610 }
Jason parks56aa5322011-01-07 09:01:15 -06002611 } catch (NativeDaemonConnectorException e) {
2612 // Encryption failed
2613 return e.getCode();
2614 }
2615
2616 return 0;
2617 }
2618
Paul Lawrence8e397362014-01-27 15:22:30 -08002619 /** Set the password for encrypting the master key.
2620 * @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
2621 * @param password The password to set.
2622 */
2623 public int changeEncryptionPassword(int type, String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002624 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2625 "no permission to access the crypt keeper");
2626
2627 waitForReady();
2628
2629 if (DEBUG_EVENTS) {
2630 Slog.i(TAG, "changing encryption password...");
2631 }
2632
2633 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002634 NativeDaemonEvent event = mCryptConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type],
Paul Lawrence05487612015-06-09 13:35:38 -07002635 new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002636 return Integer.parseInt(event.getMessage());
Jason parksf7b3cd42011-01-27 09:28:25 -06002637 } catch (NativeDaemonConnectorException e) {
2638 // Encryption failed
2639 return e.getCode();
2640 }
2641 }
2642
Christopher Tate32418be2011-10-10 13:51:12 -07002643 /**
2644 * Validate a user-supplied password string with cryptfs
2645 */
2646 @Override
2647 public int verifyEncryptionPassword(String password) throws RemoteException {
2648 // Only the system process is permitted to validate passwords
2649 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2650 throw new SecurityException("no permission to access the crypt keeper");
2651 }
2652
2653 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2654 "no permission to access the crypt keeper");
2655
2656 if (TextUtils.isEmpty(password)) {
2657 throw new IllegalArgumentException("password cannot be empty");
2658 }
2659
2660 waitForReady();
2661
2662 if (DEBUG_EVENTS) {
2663 Slog.i(TAG, "validating encryption password...");
2664 }
2665
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002666 final NativeDaemonEvent event;
Christopher Tate32418be2011-10-10 13:51:12 -07002667 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002668 event = mCryptConnector.execute("cryptfs", "verifypw", new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002669 Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
2670 return Integer.parseInt(event.getMessage());
Christopher Tate32418be2011-10-10 13:51:12 -07002671 } catch (NativeDaemonConnectorException e) {
2672 // Encryption failed
2673 return e.getCode();
2674 }
2675 }
2676
Paul Lawrence8e397362014-01-27 15:22:30 -08002677 /**
2678 * Get the type of encryption used to encrypt the master key.
2679 * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
2680 */
2681 @Override
Svetoslav16e4a1a2014-09-29 18:16:20 -07002682 public int getPasswordType() {
Paul Lawrence9de713d2016-05-02 22:45:33 +00002683 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2684 "no permission to access the crypt keeper");
2685
Paul Lawrence8e397362014-01-27 15:22:30 -08002686 waitForReady();
2687
2688 final NativeDaemonEvent event;
2689 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002690 event = mCryptConnector.execute("cryptfs", "getpwtype");
Paul Lawrence8e397362014-01-27 15:22:30 -08002691 for (int i = 0; i < CRYPTO_TYPES.length; ++i) {
2692 if (CRYPTO_TYPES[i].equals(event.getMessage()))
2693 return i;
2694 }
2695
2696 throw new IllegalStateException("unexpected return from cryptfs");
2697 } catch (NativeDaemonConnectorException e) {
2698 throw e.rethrowAsParcelableException();
2699 }
2700 }
2701
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002702 /**
2703 * Set a field in the crypto header.
2704 * @param field field to set
2705 * @param contents contents to set in field
2706 */
2707 @Override
2708 public void setField(String field, String contents) throws RemoteException {
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002709 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2710 "no permission to access the crypt keeper");
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002711
2712 waitForReady();
2713
2714 final NativeDaemonEvent event;
2715 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002716 event = mCryptConnector.execute("cryptfs", "setfield", field, contents);
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002717 } catch (NativeDaemonConnectorException e) {
2718 throw e.rethrowAsParcelableException();
2719 }
2720 }
2721
2722 /**
2723 * Gets a field from the crypto header.
2724 * @param field field to get
2725 * @return contents of field
2726 */
2727 @Override
2728 public String getField(String field) throws RemoteException {
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002729 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2730 "no permission to access the crypt keeper");
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002731
2732 waitForReady();
2733
2734 final NativeDaemonEvent event;
2735 try {
2736 final String[] contents = NativeDaemonEvent.filterMessageList(
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002737 mCryptConnector.executeForList("cryptfs", "getfield", field),
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002738 VoldResponseCode.CryptfsGetfieldResult);
2739 String result = new String();
2740 for (String content : contents) {
2741 result += content;
2742 }
2743 return result;
2744 } catch (NativeDaemonConnectorException e) {
2745 throw e.rethrowAsParcelableException();
2746 }
2747 }
2748
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002749 /**
2750 * Is userdata convertible to file based encryption?
2751 * @return non zero for convertible
2752 */
2753 @Override
2754 public boolean isConvertibleToFBE() throws RemoteException {
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002755 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2756 "no permission to access the crypt keeper");
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002757
2758 waitForReady();
2759
2760 final NativeDaemonEvent event;
2761 try {
2762 event = mCryptConnector.execute("cryptfs", "isConvertibleToFBE");
2763 return Integer.parseInt(event.getMessage()) != 0;
2764 } catch (NativeDaemonConnectorException e) {
2765 throw e.rethrowAsParcelableException();
2766 }
2767 }
2768
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002769 @Override
Paul Lawrence945490c2014-03-27 16:37:28 +00002770 public String getPassword() throws RemoteException {
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002771 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
Rubin Xucd7a0142015-04-17 23:45:27 +01002772 "only keyguard can retrieve password");
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002773
Paul Lawrence945490c2014-03-27 16:37:28 +00002774 if (!isReady()) {
2775 return new String();
2776 }
2777
2778 final NativeDaemonEvent event;
2779 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002780 event = mCryptConnector.execute("cryptfs", "getpw");
Paul Lawrence24063b52015-01-06 13:11:23 -08002781 if ("-1".equals(event.getMessage())) {
2782 // -1 equals no password
2783 return null;
2784 }
Paul Lawrence05487612015-06-09 13:35:38 -07002785 return event.getMessage();
Paul Lawrence945490c2014-03-27 16:37:28 +00002786 } catch (NativeDaemonConnectorException e) {
2787 throw e.rethrowAsParcelableException();
Paul Lawrence24063b52015-01-06 13:11:23 -08002788 } catch (IllegalArgumentException e) {
2789 Slog.e(TAG, "Invalid response to getPassword");
2790 return null;
Paul Lawrence945490c2014-03-27 16:37:28 +00002791 }
2792 }
2793
2794 @Override
2795 public void clearPassword() throws RemoteException {
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002796 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2797 "only keyguard can clear password");
2798
Paul Lawrence945490c2014-03-27 16:37:28 +00002799 if (!isReady()) {
2800 return;
2801 }
2802
2803 final NativeDaemonEvent event;
2804 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002805 event = mCryptConnector.execute("cryptfs", "clearpw");
Paul Lawrence945490c2014-03-27 16:37:28 +00002806 } catch (NativeDaemonConnectorException e) {
2807 throw e.rethrowAsParcelableException();
2808 }
2809 }
2810
2811 @Override
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002812 public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002813 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002814 waitForReady();
2815
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002816 try {
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002817 mCryptConnector.execute("cryptfs", "create_user_key", userId, serialNumber,
2818 ephemeral ? 1 : 0);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002819 } catch (NativeDaemonConnectorException e) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002820 throw e.rethrowAsParcelableException();
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002821 }
2822 }
2823
Paul Crowley7ec733f2015-05-19 12:42:00 +01002824 @Override
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002825 public void destroyUserKey(int userId) {
2826 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowley7ec733f2015-05-19 12:42:00 +01002827 waitForReady();
2828
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002829 try {
2830 mCryptConnector.execute("cryptfs", "destroy_user_key", userId);
2831 } catch (NativeDaemonConnectorException e) {
2832 throw e.rethrowAsParcelableException();
2833 }
2834 }
2835
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002836 private SensitiveArg encodeBytes(byte[] bytes) {
2837 if (ArrayUtils.isEmpty(bytes)) {
2838 return new SensitiveArg("!");
2839 } else {
2840 return new SensitiveArg(HexDump.toHexString(bytes));
2841 }
2842 }
2843
Paul Crowleycc701552016-05-17 14:18:49 -07002844 /*
2845 * Add this token/secret pair to the set of ways we can recover a disk encryption key.
2846 * Changing the token/secret for a disk encryption key is done in two phases: first, adding
2847 * a new token/secret pair with this call, then delting all other pairs with
2848 * fixateNewestUserKeyAuth. This allows other places where a credential is used, such as
2849 * Gatekeeper, to be updated between the two calls.
2850 */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002851 @Override
Paul Crowleycc701552016-05-17 14:18:49 -07002852 public void addUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002853 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2854 waitForReady();
2855
2856 try {
Paul Crowleycc701552016-05-17 14:18:49 -07002857 mCryptConnector.execute("cryptfs", "add_user_key_auth", userId, serialNumber,
2858 encodeBytes(token), encodeBytes(secret));
2859 } catch (NativeDaemonConnectorException e) {
2860 throw e.rethrowAsParcelableException();
2861 }
2862 }
2863
2864 /*
2865 * Delete all disk encryption token/secret pairs except the most recently added one
2866 */
2867 @Override
2868 public void fixateNewestUserKeyAuth(int userId) {
2869 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2870 waitForReady();
2871
2872 try {
2873 mCryptConnector.execute("cryptfs", "fixate_newest_user_key_auth", userId);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002874 } catch (NativeDaemonConnectorException e) {
2875 throw e.rethrowAsParcelableException();
2876 }
2877 }
2878
2879 @Override
2880 public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002881 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2882 waitForReady();
2883
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002884 if (StorageManager.isFileEncryptedNativeOrEmulated()) {
2885 // When a user has secure lock screen, require a challenge token to
2886 // actually unlock. This check is mostly in place for emulation mode.
2887 if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(token)) {
2888 throw new IllegalStateException("Token required to unlock secure user " + userId);
2889 }
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07002890
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002891 try {
2892 mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber,
2893 encodeBytes(token), encodeBytes(secret));
2894 } catch (NativeDaemonConnectorException e) {
2895 throw e.rethrowAsParcelableException();
2896 }
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002897 }
2898
2899 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002900 mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002901 }
2902 }
2903
2904 @Override
2905 public void lockUserKey(int userId) {
2906 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2907 waitForReady();
2908
2909 try {
2910 mCryptConnector.execute("cryptfs", "lock_user_key", userId);
2911 } catch (NativeDaemonConnectorException e) {
2912 throw e.rethrowAsParcelableException();
2913 }
2914
2915 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002916 mLocalUnlockedUsers = ArrayUtils.removeInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002917 }
2918 }
2919
2920 @Override
2921 public boolean isUserKeyUnlocked(int userId) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002922 synchronized (mLock) {
2923 return ArrayUtils.contains(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002924 }
2925 }
2926
2927 @Override
Jeff Sharkey47f71082016-02-01 17:03:54 -07002928 public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002929 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2930 waitForReady();
2931
2932 try {
2933 mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid),
Jeff Sharkey47f71082016-02-01 17:03:54 -07002934 userId, serialNumber, flags);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002935 } catch (NativeDaemonConnectorException e) {
2936 throw e.rethrowAsParcelableException();
Paul Crowley7ec733f2015-05-19 12:42:00 +01002937 }
2938 }
2939
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002940 @Override
Jeff Sharkeyfcf1e552016-04-14 20:44:58 -06002941 public void destroyUserStorage(String volumeUuid, int userId, int flags) {
2942 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2943 waitForReady();
2944
2945 try {
2946 mCryptConnector.execute("cryptfs", "destroy_user_storage", escapeNull(volumeUuid),
2947 userId, flags);
2948 } catch (NativeDaemonConnectorException e) {
2949 throw e.rethrowAsParcelableException();
2950 }
2951 }
2952
2953 @Override
Daichi Hirono91e3b502015-12-16 09:24:16 +09002954 public ParcelFileDescriptor mountAppFuse(final String name) throws RemoteException {
Daichi Hironobee50c02015-12-14 11:00:54 +09002955 try {
Daichi Hirono91e3b502015-12-16 09:24:16 +09002956 final int uid = Binder.getCallingUid();
Daichi Hironofd7d57e2016-01-29 14:30:58 +09002957 final int pid = Binder.getCallingPid();
Daichi Hironobee50c02015-12-14 11:00:54 +09002958 final NativeDaemonEvent event =
Daichi Hironofd7d57e2016-01-29 14:30:58 +09002959 mConnector.execute("appfuse", "mount", uid, pid, name);
Daichi Hironobee50c02015-12-14 11:00:54 +09002960 if (event.getFileDescriptors() == null) {
Daichi Hirono91e3b502015-12-16 09:24:16 +09002961 throw new RemoteException("AppFuse FD from vold is null.");
Daichi Hironobee50c02015-12-14 11:00:54 +09002962 }
Daichi Hirono91e3b502015-12-16 09:24:16 +09002963 return ParcelFileDescriptor.fromFd(
2964 event.getFileDescriptors()[0],
2965 mHandler,
2966 new ParcelFileDescriptor.OnCloseListener() {
2967 @Override
2968 public void onClose(IOException e) {
2969 try {
2970 final NativeDaemonEvent event = mConnector.execute(
Daichi Hironofd7d57e2016-01-29 14:30:58 +09002971 "appfuse", "unmount", uid, pid, name);
Daichi Hirono91e3b502015-12-16 09:24:16 +09002972 } catch (NativeDaemonConnectorException unmountException) {
2973 Log.e(TAG, "Failed to unmount appfuse.");
2974 }
2975 }
2976 });
Daichi Hironobee50c02015-12-14 11:00:54 +09002977 } catch (NativeDaemonConnectorException e) {
2978 throw e.rethrowAsParcelableException();
Daichi Hirono91e3b502015-12-16 09:24:16 +09002979 } catch (IOException e) {
2980 throw new RemoteException(e.getMessage());
Daichi Hironobee50c02015-12-14 11:00:54 +09002981 }
Daichi Hirono9e8d9e22015-11-13 14:37:00 +09002982 }
2983
2984 @Override
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002985 public int mkdirs(String callingPkg, String appPath) {
2986 final int userId = UserHandle.getUserId(Binder.getCallingUid());
2987 final UserEnvironment userEnv = new UserEnvironment(userId);
2988
2989 // Validate that reported package name belongs to caller
2990 final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
2991 Context.APP_OPS_SERVICE);
2992 appOps.checkPackage(Binder.getCallingUid(), callingPkg);
2993
Jeff Sharkey48877892015-03-18 11:27:19 -07002994 File appFile = null;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002995 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07002996 appFile = new File(appPath).getCanonicalFile();
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002997 } catch (IOException e) {
2998 Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
2999 return -1;
3000 }
3001
3002 // Try translating the app path into a vold path, but require that it
3003 // belong to the calling package.
Jeff Sharkey48877892015-03-18 11:27:19 -07003004 if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) ||
3005 FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) ||
3006 FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) {
3007 appPath = appFile.getAbsolutePath();
3008 if (!appPath.endsWith("/")) {
3009 appPath = appPath + "/";
3010 }
3011
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003012 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07003013 mConnector.execute("volume", "mkdirs", appPath);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003014 return 0;
3015 } catch (NativeDaemonConnectorException e) {
3016 return e.getCode();
3017 }
3018 }
3019
Jeff Sharkey48877892015-03-18 11:27:19 -07003020 throw new SecurityException("Invalid mkdirs path: " + appFile);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003021 }
3022
3023 @Override
Jeff Sharkey46349872015-07-28 10:49:47 -07003024 public StorageVolume[] getVolumeList(int uid, String packageName, int flags) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003025 final int userId = UserHandle.getUserId(uid);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003026
Jeff Sharkey46349872015-07-28 10:49:47 -07003027 final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0;
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003028 final boolean realState = (flags & StorageManager.FLAG_REAL_STATE) != 0;
3029 final boolean includeInvisible = (flags & StorageManager.FLAG_INCLUDE_INVISIBLE) != 0;
Jeff Sharkey46349872015-07-28 10:49:47 -07003030
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003031 final boolean userKeyUnlocked;
3032 final boolean storagePermission;
3033 final long token = Binder.clearCallingIdentity();
Svetoslav38c3dbb2015-07-14 11:27:06 -07003034 try {
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003035 userKeyUnlocked = isUserKeyUnlocked(userId);
3036 storagePermission = mMountServiceInternal.hasExternalStorage(uid, packageName);
Svetoslav38c3dbb2015-07-14 11:27:06 -07003037 } finally {
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003038 Binder.restoreCallingIdentity(token);
Svetoslav38c3dbb2015-07-14 11:27:06 -07003039 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003040
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003041 boolean foundPrimary = false;
3042
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003043 final ArrayList<StorageVolume> res = new ArrayList<>();
Jeff Sharkey48877892015-03-18 11:27:19 -07003044 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003045 for (int i = 0; i < mVolumes.size(); i++) {
3046 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003047 switch (vol.getType()) {
3048 case VolumeInfo.TYPE_PUBLIC:
3049 case VolumeInfo.TYPE_EMULATED:
3050 break;
3051 default:
3052 continue;
3053 }
3054
3055 boolean match = false;
3056 if (forWrite) {
3057 match = vol.isVisibleForWrite(userId);
3058 } else {
Felipe Leme123a0e72016-06-10 11:09:11 -07003059 match = vol.isVisibleForRead(userId)
3060 || (includeInvisible && vol.getPath() != null);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003061 }
3062 if (!match) continue;
3063
3064 boolean reportUnmounted = false;
3065 if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !userKeyUnlocked) {
3066 reportUnmounted = true;
3067 } else if (!storagePermission && !realState) {
3068 reportUnmounted = true;
3069 }
3070
3071 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
3072 reportUnmounted);
3073 if (vol.isPrimary()) {
3074 res.add(0, userVol);
3075 foundPrimary = true;
3076 } else {
3077 res.add(userVol);
Jeff Sharkeyb049e212012-09-07 23:16:01 -07003078 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003079 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003080 }
Jeff Sharkey48877892015-03-18 11:27:19 -07003081
3082 if (!foundPrimary) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003083 Log.w(TAG, "No primary storage defined yet; hacking together a stub");
Jeff Sharkey48877892015-03-18 11:27:19 -07003084
3085 final boolean primaryPhysical = SystemProperties.getBoolean(
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003086 StorageManager.PROP_PRIMARY_PHYSICAL, false);
Jeff Sharkey48877892015-03-18 11:27:19 -07003087
3088 final String id = "stub_primary";
3089 final File path = Environment.getLegacyExternalStorageDirectory();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003090 final String description = mContext.getString(android.R.string.unknownName);
Jeff Sharkey48877892015-03-18 11:27:19 -07003091 final boolean primary = true;
3092 final boolean removable = primaryPhysical;
3093 final boolean emulated = !primaryPhysical;
3094 final long mtpReserveSize = 0L;
3095 final boolean allowMassStorage = false;
3096 final long maxFileSize = 0L;
3097 final UserHandle owner = new UserHandle(userId);
3098 final String uuid = null;
Jeff Sharkey48877892015-03-18 11:27:19 -07003099 final String state = Environment.MEDIA_REMOVED;
3100
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07003101 res.add(0, new StorageVolume(id, StorageVolume.STORAGE_ID_INVALID, path,
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003102 description, primary, removable, emulated, mtpReserveSize,
3103 allowMassStorage, maxFileSize, owner, uuid, state));
Jeff Sharkey48877892015-03-18 11:27:19 -07003104 }
3105
3106 return res.toArray(new StorageVolume[res.size()]);
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003107 }
3108
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003109 @Override
3110 public DiskInfo[] getDisks() {
3111 synchronized (mLock) {
3112 final DiskInfo[] res = new DiskInfo[mDisks.size()];
3113 for (int i = 0; i < mDisks.size(); i++) {
3114 res[i] = mDisks.valueAt(i);
3115 }
3116 return res;
3117 }
3118 }
3119
3120 @Override
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003121 public VolumeInfo[] getVolumes(int flags) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003122 synchronized (mLock) {
3123 final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
3124 for (int i = 0; i < mVolumes.size(); i++) {
3125 res[i] = mVolumes.valueAt(i);
3126 }
3127 return res;
3128 }
3129 }
3130
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003131 @Override
3132 public VolumeRecord[] getVolumeRecords(int flags) {
3133 synchronized (mLock) {
3134 final VolumeRecord[] res = new VolumeRecord[mRecords.size()];
3135 for (int i = 0; i < mRecords.size(); i++) {
3136 res[i] = mRecords.valueAt(i);
3137 }
3138 return res;
3139 }
3140 }
3141
Kenny Rootaf9d6672010-10-08 09:21:39 -07003142 private void addObbStateLocked(ObbState obbState) throws RemoteException {
3143 final IBinder binder = obbState.getBinder();
3144 List<ObbState> obbStates = mObbMounts.get(binder);
Kenny Root5919ac62010-10-05 09:49:40 -07003145
Kenny Rootaf9d6672010-10-08 09:21:39 -07003146 if (obbStates == null) {
3147 obbStates = new ArrayList<ObbState>();
3148 mObbMounts.put(binder, obbStates);
3149 } else {
3150 for (final ObbState o : obbStates) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003151 if (o.rawPath.equals(obbState.rawPath)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003152 throw new IllegalStateException("Attempt to add ObbState twice. "
3153 + "This indicates an error in the MountService logic.");
Kenny Root5919ac62010-10-05 09:49:40 -07003154 }
3155 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003156 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003157
3158 obbStates.add(obbState);
3159 try {
3160 obbState.link();
3161 } catch (RemoteException e) {
3162 /*
3163 * The binder died before we could link it, so clean up our state
3164 * and return failure.
3165 */
3166 obbStates.remove(obbState);
3167 if (obbStates.isEmpty()) {
3168 mObbMounts.remove(binder);
3169 }
3170
3171 // Rethrow the error so mountObb can get it
3172 throw e;
3173 }
3174
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003175 mObbPathToStateMap.put(obbState.rawPath, obbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003176 }
3177
Kenny Rootaf9d6672010-10-08 09:21:39 -07003178 private void removeObbStateLocked(ObbState obbState) {
3179 final IBinder binder = obbState.getBinder();
3180 final List<ObbState> obbStates = mObbMounts.get(binder);
3181 if (obbStates != null) {
3182 if (obbStates.remove(obbState)) {
3183 obbState.unlink();
Kenny Root05105f72010-09-22 17:29:43 -07003184 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003185 if (obbStates.isEmpty()) {
3186 mObbMounts.remove(binder);
3187 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003188 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003189
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003190 mObbPathToStateMap.remove(obbState.rawPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003191 }
3192
Kenny Roota02b8b02010-08-05 16:14:17 -07003193 private class ObbActionHandler extends Handler {
3194 private boolean mBound = false;
Kenny Root480afe72010-10-07 10:17:50 -07003195 private final List<ObbAction> mActions = new LinkedList<ObbAction>();
Kenny Roota02b8b02010-08-05 16:14:17 -07003196
3197 ObbActionHandler(Looper l) {
3198 super(l);
3199 }
3200
3201 @Override
3202 public void handleMessage(Message msg) {
3203 switch (msg.what) {
3204 case OBB_RUN_ACTION: {
Kenny Root480afe72010-10-07 10:17:50 -07003205 final ObbAction action = (ObbAction) msg.obj;
Kenny Roota02b8b02010-08-05 16:14:17 -07003206
3207 if (DEBUG_OBB)
3208 Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
3209
3210 // If a bind was already initiated we don't really
3211 // need to do anything. The pending install
3212 // will be processed later on.
3213 if (!mBound) {
3214 // If this is the only one pending we might
3215 // have to bind to the service again.
3216 if (!connectToService()) {
3217 Slog.e(TAG, "Failed to bind to media container service");
3218 action.handleError();
3219 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003220 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003221 }
Kenny Root735de3b2010-09-30 14:11:39 -07003222
Kenny Root735de3b2010-09-30 14:11:39 -07003223 mActions.add(action);
Kenny Roota02b8b02010-08-05 16:14:17 -07003224 break;
3225 }
3226 case OBB_MCS_BOUND: {
3227 if (DEBUG_OBB)
3228 Slog.i(TAG, "OBB_MCS_BOUND");
3229 if (msg.obj != null) {
3230 mContainerService = (IMediaContainerService) msg.obj;
3231 }
3232 if (mContainerService == null) {
3233 // Something seriously wrong. Bail out
3234 Slog.e(TAG, "Cannot bind to media container service");
3235 for (ObbAction action : mActions) {
3236 // Indicate service bind error
3237 action.handleError();
3238 }
3239 mActions.clear();
3240 } else if (mActions.size() > 0) {
Kenny Root480afe72010-10-07 10:17:50 -07003241 final ObbAction action = mActions.get(0);
Kenny Roota02b8b02010-08-05 16:14:17 -07003242 if (action != null) {
3243 action.execute(this);
3244 }
3245 } else {
3246 // Should never happen ideally.
3247 Slog.w(TAG, "Empty queue");
3248 }
3249 break;
3250 }
3251 case OBB_MCS_RECONNECT: {
3252 if (DEBUG_OBB)
3253 Slog.i(TAG, "OBB_MCS_RECONNECT");
3254 if (mActions.size() > 0) {
3255 if (mBound) {
3256 disconnectService();
3257 }
3258 if (!connectToService()) {
3259 Slog.e(TAG, "Failed to bind to media container service");
3260 for (ObbAction action : mActions) {
3261 // Indicate service bind error
3262 action.handleError();
3263 }
3264 mActions.clear();
3265 }
3266 }
3267 break;
3268 }
3269 case OBB_MCS_UNBIND: {
3270 if (DEBUG_OBB)
3271 Slog.i(TAG, "OBB_MCS_UNBIND");
3272
3273 // Delete pending install
3274 if (mActions.size() > 0) {
3275 mActions.remove(0);
3276 }
3277 if (mActions.size() == 0) {
3278 if (mBound) {
3279 disconnectService();
3280 }
3281 } else {
3282 // There are more pending requests in queue.
3283 // Just post MCS_BOUND message to trigger processing
3284 // of next pending install.
3285 mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
3286 }
3287 break;
3288 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003289 case OBB_FLUSH_MOUNT_STATE: {
3290 final String path = (String) msg.obj;
3291
3292 if (DEBUG_OBB)
3293 Slog.i(TAG, "Flushing all OBB state for path " + path);
3294
3295 synchronized (mObbMounts) {
3296 final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
3297
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003298 final Iterator<ObbState> i = mObbPathToStateMap.values().iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003299 while (i.hasNext()) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003300 final ObbState state = i.next();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003301
3302 /*
3303 * If this entry's source file is in the volume path
3304 * that got unmounted, remove it because it's no
3305 * longer valid.
3306 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003307 if (state.canonicalPath.startsWith(path)) {
3308 obbStatesToRemove.add(state);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003309 }
3310 }
3311
3312 for (final ObbState obbState : obbStatesToRemove) {
3313 if (DEBUG_OBB)
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003314 Slog.i(TAG, "Removing state for " + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003315
3316 removeObbStateLocked(obbState);
3317
3318 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003319 obbState.token.onObbResult(obbState.rawPath, obbState.nonce,
Kenny Rootaf9d6672010-10-08 09:21:39 -07003320 OnObbStateChangeListener.UNMOUNTED);
3321 } catch (RemoteException e) {
3322 Slog.i(TAG, "Couldn't send unmount notification for OBB: "
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003323 + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003324 }
3325 }
3326 }
3327 break;
3328 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003329 }
3330 }
3331
3332 private boolean connectToService() {
3333 if (DEBUG_OBB)
3334 Slog.i(TAG, "Trying to bind to DefaultContainerService");
3335
3336 Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Jeff Sharkey6dce4962015-07-03 18:08:41 -07003337 if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE,
Xiaohui Chene4de5a02015-09-22 15:33:31 -07003338 UserHandle.SYSTEM)) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003339 mBound = true;
3340 return true;
3341 }
3342 return false;
3343 }
3344
3345 private void disconnectService() {
3346 mContainerService = null;
3347 mBound = false;
3348 mContext.unbindService(mDefContainerConn);
3349 }
3350 }
3351
3352 abstract class ObbAction {
3353 private static final int MAX_RETRIES = 3;
3354 private int mRetries;
3355
3356 ObbState mObbState;
3357
3358 ObbAction(ObbState obbState) {
3359 mObbState = obbState;
3360 }
3361
3362 public void execute(ObbActionHandler handler) {
3363 try {
3364 if (DEBUG_OBB)
Ben Komalo444eca22011-09-01 15:17:44 -07003365 Slog.i(TAG, "Starting to execute action: " + toString());
Kenny Roota02b8b02010-08-05 16:14:17 -07003366 mRetries++;
3367 if (mRetries > MAX_RETRIES) {
3368 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
Kenny Root480afe72010-10-07 10:17:50 -07003369 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003370 handleError();
Kenny Roota02b8b02010-08-05 16:14:17 -07003371 } else {
3372 handleExecute();
3373 if (DEBUG_OBB)
3374 Slog.i(TAG, "Posting install MCS_UNBIND");
3375 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
3376 }
3377 } catch (RemoteException e) {
3378 if (DEBUG_OBB)
3379 Slog.i(TAG, "Posting install MCS_RECONNECT");
3380 mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
3381 } catch (Exception e) {
3382 if (DEBUG_OBB)
3383 Slog.d(TAG, "Error handling OBB action", e);
3384 handleError();
Kenny Root17eb6fb2010-10-06 15:02:52 -07003385 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003386 }
3387 }
3388
Kenny Root05105f72010-09-22 17:29:43 -07003389 abstract void handleExecute() throws RemoteException, IOException;
Kenny Roota02b8b02010-08-05 16:14:17 -07003390 abstract void handleError();
Kenny Root38cf8862010-09-26 14:18:51 -07003391
3392 protected ObbInfo getObbInfo() throws IOException {
3393 ObbInfo obbInfo;
3394 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003395 obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003396 } catch (RemoteException e) {
3397 Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003398 + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003399 obbInfo = null;
3400 }
3401 if (obbInfo == null) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003402 throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003403 }
3404 return obbInfo;
3405 }
3406
Kenny Rootaf9d6672010-10-08 09:21:39 -07003407 protected void sendNewStatusOrIgnore(int status) {
3408 if (mObbState == null || mObbState.token == null) {
3409 return;
3410 }
3411
Kenny Root38cf8862010-09-26 14:18:51 -07003412 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003413 mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
Kenny Root38cf8862010-09-26 14:18:51 -07003414 } catch (RemoteException e) {
3415 Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
3416 }
3417 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003418 }
3419
3420 class MountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003421 private final String mKey;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003422 private final int mCallingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003423
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003424 MountObbAction(ObbState obbState, String key, int callingUid) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003425 super(obbState);
3426 mKey = key;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003427 mCallingUid = callingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003428 }
3429
Jason parks5af0b912010-11-29 09:05:25 -06003430 @Override
Kenny Root735de3b2010-09-30 14:11:39 -07003431 public void handleExecute() throws IOException, RemoteException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003432 waitForReady();
3433 warnOnNotMounted();
3434
Kenny Root38cf8862010-09-26 14:18:51 -07003435 final ObbInfo obbInfo = getObbInfo();
3436
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003437 if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003438 Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
3439 + " which is owned by " + obbInfo.packageName);
3440 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3441 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003442 }
3443
Kenny Rootaf9d6672010-10-08 09:21:39 -07003444 final boolean isMounted;
3445 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003446 isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003447 }
3448 if (isMounted) {
3449 Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
3450 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
3451 return;
3452 }
3453
Kenny Rootaf9d6672010-10-08 09:21:39 -07003454 final String hashedKey;
3455 if (mKey == null) {
3456 hashedKey = "none";
3457 } else {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003458 try {
Kenny Root3b1abba2010-10-13 15:00:07 -07003459 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
3460
3461 KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
3462 PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
3463 SecretKey key = factory.generateSecret(ks);
3464 BigInteger bi = new BigInteger(key.getEncoded());
3465 hashedKey = bi.toString(16);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003466 } catch (NoSuchAlgorithmException e) {
Kenny Root3b1abba2010-10-13 15:00:07 -07003467 Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
3468 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
3469 return;
3470 } catch (InvalidKeySpecException e) {
3471 Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
3472 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root38cf8862010-09-26 14:18:51 -07003473 return;
3474 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003475 }
Kenny Root38cf8862010-09-26 14:18:51 -07003476
Kenny Rootaf9d6672010-10-08 09:21:39 -07003477 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003478 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003479 mConnector.execute("obb", "mount", mObbState.canonicalPath, new SensitiveArg(hashedKey),
Jeff Sharkey56cd6462013-06-07 15:09:15 -07003480 mObbState.ownerGid);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003481 } catch (NativeDaemonConnectorException e) {
3482 int code = e.getCode();
3483 if (code != VoldResponseCode.OpFailedStorageBusy) {
3484 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003485 }
3486 }
3487
Kenny Rootaf9d6672010-10-08 09:21:39 -07003488 if (rc == StorageResultCode.OperationSucceeded) {
3489 if (DEBUG_OBB)
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003490 Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003491
3492 synchronized (mObbMounts) {
3493 addObbStateLocked(mObbState);
3494 }
3495
3496 sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
Kenny Root02c87302010-07-01 08:10:18 -07003497 } else {
Kenny Root05105f72010-09-22 17:29:43 -07003498 Slog.e(TAG, "Couldn't mount OBB file: " + rc);
Kenny Roota02b8b02010-08-05 16:14:17 -07003499
Kenny Rootaf9d6672010-10-08 09:21:39 -07003500 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
Kenny Root02c87302010-07-01 08:10:18 -07003501 }
3502 }
3503
Jason parks5af0b912010-11-29 09:05:25 -06003504 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003505 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003506 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root02c87302010-07-01 08:10:18 -07003507 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003508
3509 @Override
3510 public String toString() {
3511 StringBuilder sb = new StringBuilder();
3512 sb.append("MountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003513 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003514 sb.append('}');
3515 return sb.toString();
3516 }
3517 }
3518
3519 class UnmountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003520 private final boolean mForceUnmount;
Kenny Roota02b8b02010-08-05 16:14:17 -07003521
3522 UnmountObbAction(ObbState obbState, boolean force) {
3523 super(obbState);
3524 mForceUnmount = force;
3525 }
3526
Jason parks5af0b912010-11-29 09:05:25 -06003527 @Override
Kenny Root38cf8862010-09-26 14:18:51 -07003528 public void handleExecute() throws IOException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003529 waitForReady();
3530 warnOnNotMounted();
3531
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003532 final ObbState existingState;
Kenny Root38cf8862010-09-26 14:18:51 -07003533 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003534 existingState = mObbPathToStateMap.get(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003535 }
Kenny Root38cf8862010-09-26 14:18:51 -07003536
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003537 if (existingState == null) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003538 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
3539 return;
3540 }
3541
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003542 if (existingState.ownerGid != mObbState.ownerGid) {
3543 Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
3544 + " (owned by GID " + existingState.ownerGid + ")");
Kenny Rootaf9d6672010-10-08 09:21:39 -07003545 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3546 return;
3547 }
3548
Kenny Rootaf9d6672010-10-08 09:21:39 -07003549 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003550 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003551 final Command cmd = new Command("obb", "unmount", mObbState.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08003552 if (mForceUnmount) {
3553 cmd.appendArg("force");
3554 }
3555 mConnector.execute(cmd);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003556 } catch (NativeDaemonConnectorException e) {
3557 int code = e.getCode();
3558 if (code == VoldResponseCode.OpFailedStorageBusy) {
3559 rc = StorageResultCode.OperationFailedStorageBusy;
3560 } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
3561 // If it's not mounted then we've already won.
3562 rc = StorageResultCode.OperationSucceeded;
3563 } else {
3564 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003565 }
3566 }
3567
Kenny Rootaf9d6672010-10-08 09:21:39 -07003568 if (rc == StorageResultCode.OperationSucceeded) {
3569 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003570 removeObbStateLocked(existingState);
Kenny Root38cf8862010-09-26 14:18:51 -07003571 }
3572
Kenny Rootaf9d6672010-10-08 09:21:39 -07003573 sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
Kenny Roota02b8b02010-08-05 16:14:17 -07003574 } else {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003575 Slog.w(TAG, "Could not unmount OBB: " + existingState);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003576 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
Kenny Roota02b8b02010-08-05 16:14:17 -07003577 }
3578 }
3579
Jason parks5af0b912010-11-29 09:05:25 -06003580 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003581 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003582 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Roota02b8b02010-08-05 16:14:17 -07003583 }
3584
3585 @Override
3586 public String toString() {
3587 StringBuilder sb = new StringBuilder();
3588 sb.append("UnmountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003589 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003590 sb.append(",force=");
3591 sb.append(mForceUnmount);
Kenny Roota02b8b02010-08-05 16:14:17 -07003592 sb.append('}');
3593 return sb.toString();
3594 }
Kenny Root02c87302010-07-01 08:10:18 -07003595 }
Kenny Root38cf8862010-09-26 14:18:51 -07003596
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003597 private static class Callbacks extends Handler {
3598 private static final int MSG_STORAGE_STATE_CHANGED = 1;
3599 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003600 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
3601 private static final int MSG_VOLUME_FORGOTTEN = 4;
3602 private static final int MSG_DISK_SCANNED = 5;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003603 private static final int MSG_DISK_DESTROYED = 6;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003604
3605 private final RemoteCallbackList<IMountServiceListener>
3606 mCallbacks = new RemoteCallbackList<>();
3607
3608 public Callbacks(Looper looper) {
3609 super(looper);
3610 }
3611
3612 public void register(IMountServiceListener callback) {
3613 mCallbacks.register(callback);
3614 }
3615
3616 public void unregister(IMountServiceListener callback) {
3617 mCallbacks.unregister(callback);
3618 }
3619
3620 @Override
3621 public void handleMessage(Message msg) {
3622 final SomeArgs args = (SomeArgs) msg.obj;
3623 final int n = mCallbacks.beginBroadcast();
3624 for (int i = 0; i < n; i++) {
3625 final IMountServiceListener callback = mCallbacks.getBroadcastItem(i);
3626 try {
3627 invokeCallback(callback, msg.what, args);
3628 } catch (RemoteException ignored) {
3629 }
3630 }
3631 mCallbacks.finishBroadcast();
3632 args.recycle();
3633 }
3634
3635 private void invokeCallback(IMountServiceListener callback, int what, SomeArgs args)
3636 throws RemoteException {
3637 switch (what) {
3638 case MSG_STORAGE_STATE_CHANGED: {
3639 callback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
3640 (String) args.arg3);
3641 break;
3642 }
3643 case MSG_VOLUME_STATE_CHANGED: {
3644 callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
3645 break;
3646 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07003647 case MSG_VOLUME_RECORD_CHANGED: {
3648 callback.onVolumeRecordChanged((VolumeRecord) args.arg1);
3649 break;
3650 }
3651 case MSG_VOLUME_FORGOTTEN: {
3652 callback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003653 break;
3654 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003655 case MSG_DISK_SCANNED: {
3656 callback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003657 break;
3658 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003659 case MSG_DISK_DESTROYED: {
3660 callback.onDiskDestroyed((DiskInfo) args.arg1);
3661 break;
3662 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003663 }
3664 }
3665
3666 private void notifyStorageStateChanged(String path, String oldState, String newState) {
3667 final SomeArgs args = SomeArgs.obtain();
3668 args.arg1 = path;
3669 args.arg2 = oldState;
3670 args.arg3 = newState;
3671 obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
3672 }
3673
3674 private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
3675 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003676 args.arg1 = vol.clone();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003677 args.argi2 = oldState;
3678 args.argi3 = newState;
3679 obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
3680 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003681
Jeff Sharkey50a05452015-04-29 11:24:52 -07003682 private void notifyVolumeRecordChanged(VolumeRecord rec) {
3683 final SomeArgs args = SomeArgs.obtain();
3684 args.arg1 = rec.clone();
3685 obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
3686 }
3687
3688 private void notifyVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003689 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003690 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003691 obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003692 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003693
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003694 private void notifyDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003695 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003696 args.arg1 = disk.clone();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003697 args.argi2 = volumeCount;
3698 obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003699 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003700
3701 private void notifyDiskDestroyed(DiskInfo disk) {
3702 final SomeArgs args = SomeArgs.obtain();
3703 args.arg1 = disk.clone();
3704 obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
3705 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003706 }
3707
Kenny Root38cf8862010-09-26 14:18:51 -07003708 @Override
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003709 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
3710 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
3711
3712 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003713 synchronized (mLock) {
3714 pw.println("Disks:");
3715 pw.increaseIndent();
3716 for (int i = 0; i < mDisks.size(); i++) {
3717 final DiskInfo disk = mDisks.valueAt(i);
3718 disk.dump(pw);
3719 }
3720 pw.decreaseIndent();
3721
3722 pw.println();
3723 pw.println("Volumes:");
3724 pw.increaseIndent();
3725 for (int i = 0; i < mVolumes.size(); i++) {
3726 final VolumeInfo vol = mVolumes.valueAt(i);
3727 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue;
3728 vol.dump(pw);
3729 }
3730 pw.decreaseIndent();
3731
3732 pw.println();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003733 pw.println("Records:");
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003734 pw.increaseIndent();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003735 for (int i = 0; i < mRecords.size(); i++) {
3736 final VolumeRecord note = mRecords.valueAt(i);
3737 note.dump(pw);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003738 }
3739 pw.decreaseIndent();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07003740
3741 pw.println();
3742 pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
Felipe Lemec0d3f0e2016-10-10 17:12:20 -07003743 final Pair<String, Long> pair = StorageManager.getPrimaryStoragePathAndSize();
3744 if (pair == null) {
3745 pw.println("Internal storage total size: N/A");
3746 } else {
3747 pw.print("Internal storage (");
3748 pw.print(pair.first);
3749 pw.print(") total size: ");
3750 pw.print(pair.second);
3751 pw.print(" (");
3752 pw.print((float) pair.second / TrafficStats.GB_IN_BYTES);
3753 pw.println(" GB)");
3754 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07003755 pw.println("Force adoptable: " + mForceAdoptable);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08003756 pw.println();
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003757 pw.println("Local unlocked users: " + Arrays.toString(mLocalUnlockedUsers));
3758 pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003759 }
Kenny Root38cf8862010-09-26 14:18:51 -07003760
Kenny Root38cf8862010-09-26 14:18:51 -07003761 synchronized (mObbMounts) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003762 pw.println();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003763 pw.println("mObbMounts:");
3764 pw.increaseIndent();
3765 final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet()
3766 .iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003767 while (binders.hasNext()) {
3768 Entry<IBinder, List<ObbState>> e = binders.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003769 pw.println(e.getKey() + ":");
3770 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003771 final List<ObbState> obbStates = e.getValue();
Kenny Root38cf8862010-09-26 14:18:51 -07003772 for (final ObbState obbState : obbStates) {
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003773 pw.println(obbState);
Kenny Root38cf8862010-09-26 14:18:51 -07003774 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003775 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003776 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003777 pw.decreaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003778
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003779 pw.println();
3780 pw.println("mObbPathToStateMap:");
3781 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003782 final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
3783 while (maps.hasNext()) {
3784 final Entry<String, ObbState> e = maps.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003785 pw.print(e.getKey());
3786 pw.print(" -> ");
3787 pw.println(e.getValue());
Kenny Rootaf9d6672010-10-08 09:21:39 -07003788 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003789 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003790 }
Kenny Root4161f9b2011-07-13 09:48:33 -07003791
Robert Greenwalt470fd722012-01-18 12:51:15 -08003792 pw.println();
Jeff Sharkey5b0e5202015-12-18 17:18:09 -07003793 pw.println("mConnector:");
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003794 pw.increaseIndent();
Robert Greenwalt470fd722012-01-18 12:51:15 -08003795 mConnector.dump(fd, pw, args);
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003796 pw.decreaseIndent();
Christopher Tate7265abe2014-11-21 13:54:45 -08003797
Christopher Tate7265abe2014-11-21 13:54:45 -08003798 pw.println();
Jeff Sharkey5b0e5202015-12-18 17:18:09 -07003799 pw.println("mCryptConnector:");
3800 pw.increaseIndent();
3801 mCryptConnector.dump(fd, pw, args);
3802 pw.decreaseIndent();
3803
3804 pw.println();
Christopher Tate7265abe2014-11-21 13:54:45 -08003805 pw.print("Last maintenance: ");
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07003806 pw.println(TimeUtils.formatForLogging(mLastMaintenance));
Kenny Root38cf8862010-09-26 14:18:51 -07003807 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003808
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003809 /** {@inheritDoc} */
Jeff Sharkey48877892015-03-18 11:27:19 -07003810 @Override
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003811 public void monitor() {
3812 if (mConnector != null) {
3813 mConnector.monitor();
3814 }
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07003815 if (mCryptConnector != null) {
3816 mCryptConnector.monitor();
3817 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003818 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003819
3820 private final class MountServiceInternalImpl extends MountServiceInternal {
3821 // Not guarded by a lock.
3822 private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
3823 new CopyOnWriteArrayList<>();
3824
3825 @Override
3826 public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
3827 // No locking - CopyOnWriteArrayList
3828 mPolicies.add(policy);
3829 }
3830
3831 @Override
3832 public void onExternalStoragePolicyChanged(int uid, String packageName) {
3833 final int mountMode = getExternalStorageMountMode(uid, packageName);
3834 remountUidExternalStorage(uid, mountMode);
3835 }
3836
3837 @Override
3838 public int getExternalStorageMountMode(int uid, String packageName) {
3839 // No locking - CopyOnWriteArrayList
3840 int mountMode = Integer.MAX_VALUE;
3841 for (ExternalStorageMountPolicy policy : mPolicies) {
3842 final int policyMode = policy.getMountMode(uid, packageName);
3843 if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
3844 return Zygote.MOUNT_EXTERNAL_NONE;
3845 }
3846 mountMode = Math.min(mountMode, policyMode);
3847 }
3848 if (mountMode == Integer.MAX_VALUE) {
3849 return Zygote.MOUNT_EXTERNAL_NONE;
3850 }
3851 return mountMode;
3852 }
3853
3854 public boolean hasExternalStorage(int uid, String packageName) {
Amith Yamasani2bd5cff2015-07-22 14:42:31 -07003855 // No need to check for system uid. This avoids a deadlock between
3856 // PackageManagerService and AppOpsService.
3857 if (uid == Process.SYSTEM_UID) {
3858 return true;
3859 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003860 // No locking - CopyOnWriteArrayList
3861 for (ExternalStorageMountPolicy policy : mPolicies) {
3862 final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
3863 if (!policyHasStorage) {
3864 return false;
3865 }
3866 }
3867 return true;
3868 }
3869 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003870}