blob: bd43a71173d7f3c266b449072e60f9dda086f13b [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Jeff Sharkey4c099d02015-05-15 13:45:00 -070019import static com.android.internal.util.XmlUtils.readBooleanAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070020import static com.android.internal.util.XmlUtils.readIntAttribute;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070021import static com.android.internal.util.XmlUtils.readLongAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070022import static com.android.internal.util.XmlUtils.readStringAttribute;
Jeff Sharkey4c099d02015-05-15 13:45:00 -070023import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070024import static com.android.internal.util.XmlUtils.writeIntAttribute;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070025import static com.android.internal.util.XmlUtils.writeLongAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070026import static com.android.internal.util.XmlUtils.writeStringAttribute;
27import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
28import static org.xmlpull.v1.XmlPullParser.START_TAG;
29
Jason parks8888c592011-01-20 22:46:41 -060030import android.Manifest;
Jeff Sharkeyef10ee02015-07-05 14:17:27 -070031import android.annotation.Nullable;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -070032import android.app.ActivityManager;
Elliott Hughesf839b4f2014-09-26 12:30:47 -070033import android.app.ActivityManagerNative;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -070034import android.app.AppOpsManager;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070035import android.app.IActivityManager;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070036import android.content.BroadcastReceiver;
Kenny Roota02b8b02010-08-05 16:14:17 -070037import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.content.Context;
39import android.content.Intent;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070040import android.content.IntentFilter;
Kenny Roota02b8b02010-08-05 16:14:17 -070041import android.content.ServiceConnection;
Jeff Sharkey275e3e42015-04-24 16:10:32 -070042import android.content.pm.IPackageMoveObserver;
43import android.content.pm.PackageManager;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070044import android.content.pm.ProviderInfo;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070045import android.content.pm.UserInfo;
Elliott Hughesf839b4f2014-09-26 12:30:47 -070046import android.content.res.Configuration;
Kenny Root02c87302010-07-01 08:10:18 -070047import android.content.res.ObbInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.net.Uri;
Kenny Root02c87302010-07-01 08:10:18 -070049import android.os.Binder;
Jeff Sharkey4c099d02015-05-15 13:45:00 -070050import android.os.DropBoxManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070051import android.os.Environment;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070052import android.os.Environment.UserEnvironment;
Jeff Sharkey48877892015-03-18 11:27:19 -070053import android.os.FileUtils;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080054import android.os.Handler;
Dianne Hackbornefa92b22013-05-03 14:11:43 -070055import android.os.HandlerThread;
Kenny Roota02b8b02010-08-05 16:14:17 -070056import android.os.IBinder;
Daniel Sandler5f27ef42010-03-16 15:42:02 -040057import android.os.Looper;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080058import android.os.Message;
Daichi Hirono9e8d9e22015-11-13 14:37:00 +090059import android.os.ParcelFileDescriptor;
Jeff Sharkey9527b222015-06-24 15:24:48 -070060import android.os.Process;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070061import android.os.RemoteCallbackList;
San Mehat4270e1e2010-01-29 05:32:19 -080062import android.os.RemoteException;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -080063import android.os.ServiceManager;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -070064import android.os.SystemClock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070066import android.os.UserHandle;
Emily Bernier92aa5a22014-07-07 10:11:48 -040067import android.os.UserManager;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070068import android.os.storage.DiskInfo;
Kenny Roota02b8b02010-08-05 16:14:17 -070069import android.os.storage.IMountService;
70import android.os.storage.IMountServiceListener;
71import android.os.storage.IMountShutdownObserver;
72import android.os.storage.IObbActionListener;
Svet Ganov6ee871e2015-07-10 14:29:33 -070073import android.os.storage.MountServiceInternal;
Kenny Rootaf9d6672010-10-08 09:21:39 -070074import android.os.storage.OnObbStateChangeListener;
Paul Lawrence46791e72014-04-03 09:10:26 -070075import android.os.storage.StorageManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070076import android.os.storage.StorageResultCode;
Mike Lockwood2f6a3882011-05-09 19:08:06 -070077import android.os.storage.StorageVolume;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070078import android.os.storage.VolumeInfo;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070079import android.os.storage.VolumeRecord;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070080import android.provider.MediaStore;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070081import android.provider.Settings;
Jason parksf7b3cd42011-01-27 09:28:25 -060082import android.text.TextUtils;
Jeff Sharkey1783f142015-04-17 10:52:51 -070083import android.text.format.DateUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -070084import android.util.ArrayMap;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070085import android.util.AtomicFile;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070086import android.util.Log;
San Mehata5078592010-03-25 09:36:54 -070087import android.util.Slog;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070088import android.util.TimeUtils;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070089import android.util.Xml;
Jeff Sharkey48877892015-03-18 11:27:19 -070090
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070091import libcore.io.IoUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -070092import libcore.util.EmptyArray;
Mike Lockwood2f6a3882011-05-09 19:08:06 -070093
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -080094import com.android.internal.annotations.GuardedBy;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070095import com.android.internal.app.IMediaContainerService;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070096import com.android.internal.os.SomeArgs;
Jeff Sharkey9527b222015-06-24 15:24:48 -070097import com.android.internal.os.Zygote;
Jeff Sharkey48877892015-03-18 11:27:19 -070098import com.android.internal.util.ArrayUtils;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070099import com.android.internal.util.FastXmlSerializer;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800100import com.android.internal.util.HexDump;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -0700101import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700102import com.android.internal.util.Preconditions;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700103import com.android.server.NativeDaemonConnector.Command;
Jeff Sharkey56cd6462013-06-07 15:09:15 -0700104import com.android.server.NativeDaemonConnector.SensitiveArg;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700105import com.android.server.pm.PackageManagerService;
Kenny Roota02b8b02010-08-05 16:14:17 -0700106
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700107import org.xmlpull.v1.XmlPullParser;
108import org.xmlpull.v1.XmlPullParserException;
109import org.xmlpull.v1.XmlSerializer;
110
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700111import java.io.File;
Kenny Root38cf8862010-09-26 14:18:51 -0700112import java.io.FileDescriptor;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700113import java.io.FileInputStream;
114import java.io.FileNotFoundException;
Christopher Tate7265abe2014-11-21 13:54:45 -0800115import java.io.FileOutputStream;
Kenny Root05105f72010-09-22 17:29:43 -0700116import java.io.IOException;
Kenny Root38cf8862010-09-26 14:18:51 -0700117import java.io.PrintWriter;
Kenny Root3b1abba2010-10-13 15:00:07 -0700118import java.math.BigInteger;
Paul Lawrence8e397362014-01-27 15:22:30 -0800119import java.nio.charset.StandardCharsets;
Kenny Root735de3b2010-09-30 14:11:39 -0700120import java.security.NoSuchAlgorithmException;
Kenny Root3b1abba2010-10-13 15:00:07 -0700121import java.security.spec.InvalidKeySpecException;
122import java.security.spec.KeySpec;
San Mehat22dd86e2010-01-12 12:21:18 -0800123import java.util.ArrayList;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800124import java.util.Arrays;
Kenny Roota02b8b02010-08-05 16:14:17 -0700125import java.util.HashMap;
San Mehat6cdd9c02010-02-09 14:45:20 -0800126import java.util.HashSet;
Kenny Root38cf8862010-09-26 14:18:51 -0700127import java.util.Iterator;
Kenny Roota02b8b02010-08-05 16:14:17 -0700128import java.util.LinkedList;
129import java.util.List;
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700130import java.util.Locale;
Kenny Roota02b8b02010-08-05 16:14:17 -0700131import java.util.Map;
Kenny Root38cf8862010-09-26 14:18:51 -0700132import java.util.Map.Entry;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700133import java.util.Objects;
Svet Ganov6ee871e2015-07-10 14:29:33 -0700134import java.util.concurrent.CopyOnWriteArrayList;
Kenny Root51a573c2012-05-17 13:30:28 -0700135import java.util.concurrent.CountDownLatch;
136import java.util.concurrent.TimeUnit;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700137import java.util.concurrent.TimeoutException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138
Kenny Root3b1abba2010-10-13 15:00:07 -0700139import javax.crypto.SecretKey;
140import javax.crypto.SecretKeyFactory;
141import javax.crypto.spec.PBEKeySpec;
142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143/**
Jeff Sharkey48877892015-03-18 11:27:19 -0700144 * Service responsible for various storage media. Connects to {@code vold} to
145 * watch for and manage dynamically added storage, such as SD cards and USB mass
146 * storage. Also decides how storage should be presented to users on the device.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 */
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700148class MountService extends IMountService.Stub
149 implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
Jason parks5af0b912010-11-29 09:05:25 -0600150
Christopher Tated417d622013-08-19 16:14:25 -0700151 // Static direct instance pointer for the tightly-coupled idle service to use
152 static MountService sSelf = null;
153
Jeff Sharkey56e62932015-03-21 20:41:00 -0700154 public static class Lifecycle extends SystemService {
155 private MountService mMountService;
156
157 public Lifecycle(Context context) {
158 super(context);
159 }
160
161 @Override
162 public void onStart() {
163 mMountService = new MountService(getContext());
164 publishBinderService("mount", mMountService);
165 }
166
167 @Override
168 public void onBootPhase(int phase) {
169 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
170 mMountService.systemReady();
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900171 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
172 mMountService.bootCompleted();
Jeff Sharkey56e62932015-03-21 20:41:00 -0700173 }
174 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700175
176 @Override
177 public void onStartUser(int userHandle) {
178 mMountService.onStartUser(userHandle);
179 }
180
181 @Override
182 public void onCleanupUser(int userHandle) {
183 mMountService.onCleanupUser(userHandle);
184 }
Jeff Sharkey56e62932015-03-21 20:41:00 -0700185 }
186
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800187 private static final boolean DEBUG_EVENTS = false;
Kenny Rootb7db2722011-01-25 16:39:35 -0800188 private static final boolean DEBUG_OBB = false;
Kenny Root02c87302010-07-01 08:10:18 -0700189
Kenny Root07714d42011-08-17 17:49:28 -0700190 // Disable this since it messes up long-running cryptfs operations.
191 private static final boolean WATCHDOG_ENABLE = false;
192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 private static final String TAG = "MountService";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700194
Jeff Sharkey9756d752015-05-14 21:07:42 -0700195 private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700196 private static final String TAG_STORAGE_TRIM = "storage_trim";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197
Kenny Root305bcbf2010-09-03 07:56:38 -0700198 private static final String VOLD_TAG = "VoldConnector";
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700199 private static final String CRYPTD_TAG = "CryptdConnector";
Kenny Root305bcbf2010-09-03 07:56:38 -0700200
Kenny Rootcf0b38c2011-03-22 14:17:59 -0700201 /** Maximum number of ASEC containers allowed to be mounted. */
202 private static final int MAX_CONTAINERS = 250;
203
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700204 /** Magic value sent by MoveTask.cpp */
205 private static final int MOVE_STATUS_COPY_FINISHED = 82;
206
San Mehat4270e1e2010-01-29 05:32:19 -0800207 /*
208 * Internal vold response code constants
209 */
San Mehat22dd86e2010-01-12 12:21:18 -0800210 class VoldResponseCode {
San Mehat4270e1e2010-01-29 05:32:19 -0800211 /*
212 * 100 series - Requestion action was initiated; expect another reply
213 * before proceeding with a new command.
214 */
San Mehat22dd86e2010-01-12 12:21:18 -0800215 public static final int VolumeListResult = 110;
216 public static final int AsecListResult = 111;
San Mehatc1b4ce92010-02-16 17:13:03 -0800217 public static final int StorageUsersListResult = 112;
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700218 public static final int CryptfsGetfieldResult = 113;
San Mehat22dd86e2010-01-12 12:21:18 -0800219
San Mehat4270e1e2010-01-29 05:32:19 -0800220 /*
221 * 200 series - Requestion action has been successfully completed.
222 */
223 public static final int ShareStatusResult = 210;
San Mehat22dd86e2010-01-12 12:21:18 -0800224 public static final int AsecPathResult = 211;
San Mehat4270e1e2010-01-29 05:32:19 -0800225 public static final int ShareEnabledResult = 212;
San Mehat22dd86e2010-01-12 12:21:18 -0800226
San Mehat4270e1e2010-01-29 05:32:19 -0800227 /*
228 * 400 series - Command was accepted, but the requested action
229 * did not take place.
230 */
231 public static final int OpFailedNoMedia = 401;
232 public static final int OpFailedMediaBlank = 402;
233 public static final int OpFailedMediaCorrupt = 403;
234 public static final int OpFailedVolNotMounted = 404;
San Mehatd9709982010-02-18 11:43:03 -0800235 public static final int OpFailedStorageBusy = 405;
San Mehat2d66cef2010-03-23 11:12:52 -0700236 public static final int OpFailedStorageNotFound = 406;
San Mehat4270e1e2010-01-29 05:32:19 -0800237
238 /*
239 * 600 series - Unsolicited broadcasts.
240 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700241 public static final int DISK_CREATED = 640;
242 public static final int DISK_SIZE_CHANGED = 641;
243 public static final int DISK_LABEL_CHANGED = 642;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700244 public static final int DISK_SCANNED = 643;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700245 public static final int DISK_SYS_PATH_CHANGED = 644;
Jeff Sharkey48877892015-03-18 11:27:19 -0700246 public static final int DISK_DESTROYED = 649;
247
248 public static final int VOLUME_CREATED = 650;
249 public static final int VOLUME_STATE_CHANGED = 651;
250 public static final int VOLUME_FS_TYPE_CHANGED = 652;
251 public static final int VOLUME_FS_UUID_CHANGED = 653;
252 public static final int VOLUME_FS_LABEL_CHANGED = 654;
253 public static final int VOLUME_PATH_CHANGED = 655;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700254 public static final int VOLUME_INTERNAL_PATH_CHANGED = 656;
Jeff Sharkey48877892015-03-18 11:27:19 -0700255 public static final int VOLUME_DESTROYED = 659;
Svetoslavf23b64d2013-04-25 14:45:54 -0700256
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700257 public static final int MOVE_STATUS = 660;
Jeff Sharkey9756d752015-05-14 21:07:42 -0700258 public static final int BENCHMARK_RESULT = 661;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700259 public static final int TRIM_RESULT = 662;
San Mehat22dd86e2010-01-12 12:21:18 -0800260 }
261
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700262 private static final int VERSION_INIT = 1;
263 private static final int VERSION_ADD_PRIMARY = 2;
Jeff Sharkeyfced5342015-05-10 14:53:34 -0700264 private static final int VERSION_FIX_PRIMARY = 3;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700265
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700266 private static final String TAG_VOLUMES = "volumes";
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700267 private static final String ATTR_VERSION = "version";
268 private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid";
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700269 private static final String ATTR_FORCE_ADOPTABLE = "forceAdoptable";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700270 private static final String TAG_VOLUME = "volume";
271 private static final String ATTR_TYPE = "type";
272 private static final String ATTR_FS_UUID = "fsUuid";
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700273 private static final String ATTR_PART_GUID = "partGuid";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700274 private static final String ATTR_NICKNAME = "nickname";
275 private static final String ATTR_USER_FLAGS = "userFlags";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700276 private static final String ATTR_CREATED_MILLIS = "createdMillis";
277 private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis";
278 private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700279
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700280 private final AtomicFile mSettingsFile;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700281
Jeff Sharkey48877892015-03-18 11:27:19 -0700282 /**
283 * <em>Never</em> hold the lock while performing downcalls into vold, since
284 * unsolicited events can suddenly appear to update data structures.
285 */
286 private final Object mLock = new Object();
287
288 @GuardedBy("mLock")
289 private int[] mStartedUsers = EmptyArray.INT;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800290 @GuardedBy("mLock")
291 private int[] mUnlockedUsers = EmptyArray.INT;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700292
293 /** Map from disk ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700294 @GuardedBy("mLock")
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700295 private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700296 /** Map from volume ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700297 @GuardedBy("mLock")
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700298 private final ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
Jeff Sharkey48877892015-03-18 11:27:19 -0700299
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700300 /** Map from UUID to record */
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700301 @GuardedBy("mLock")
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700302 private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>();
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700303 @GuardedBy("mLock")
304 private String mPrimaryStorageUuid;
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700305 @GuardedBy("mLock")
306 private boolean mForceAdoptable;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700307
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700308 /** Map from disk ID to latches */
309 @GuardedBy("mLock")
310 private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
311
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700312 @GuardedBy("mLock")
313 private IPackageMoveObserver mMoveCallback;
314 @GuardedBy("mLock")
315 private String mMoveTargetUuid;
316
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700317 private VolumeInfo findVolumeByIdOrThrow(String id) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700318 synchronized (mLock) {
319 final VolumeInfo vol = mVolumes.get(id);
320 if (vol != null) {
321 return vol;
322 }
323 }
324 throw new IllegalArgumentException("No volume found for ID " + id);
325 }
326
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700327 private String findVolumeIdForPathOrThrow(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700328 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700329 for (int i = 0; i < mVolumes.size(); i++) {
330 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700331 if (vol.path != null && path.startsWith(vol.path)) {
332 return vol.id;
Jeff Sharkey48877892015-03-18 11:27:19 -0700333 }
334 }
335 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700336 throw new IllegalArgumentException("No volume found for path " + path);
Jeff Sharkey48877892015-03-18 11:27:19 -0700337 }
338
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700339 private VolumeRecord findRecordForPath(String path) {
340 synchronized (mLock) {
341 for (int i = 0; i < mVolumes.size(); i++) {
342 final VolumeInfo vol = mVolumes.valueAt(i);
343 if (vol.path != null && path.startsWith(vol.path)) {
344 return mRecords.get(vol.fsUuid);
345 }
346 }
347 }
348 return null;
349 }
350
351 private String scrubPath(String path) {
352 if (path.startsWith(Environment.getDataDirectory().getAbsolutePath())) {
353 return "internal";
354 }
355 final VolumeRecord rec = findRecordForPath(path);
356 if (rec == null || rec.createdMillis == 0) {
357 return "unknown";
358 } else {
359 return "ext:" + (int) ((System.currentTimeMillis() - rec.createdMillis)
360 / DateUtils.WEEK_IN_MILLIS) + "w";
361 }
362 }
363
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700364 private @Nullable VolumeInfo findStorageForUuid(String volumeUuid) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700365 final StorageManager storage = mContext.getSystemService(StorageManager.class);
366 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700367 return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL);
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700368 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
369 return storage.getPrimaryPhysicalVolume();
370 } else {
371 return storage.findEmulatedForPrivate(storage.findVolumeByUuid(volumeUuid));
372 }
373 }
374
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700375 private boolean shouldBenchmark() {
376 final long benchInterval = Settings.Global.getLong(mContext.getContentResolver(),
377 Settings.Global.STORAGE_BENCHMARK_INTERVAL, DateUtils.WEEK_IN_MILLIS);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700378 if (benchInterval == -1) {
379 return false;
380 } else if (benchInterval == 0) {
381 return true;
382 }
383
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700384 synchronized (mLock) {
385 for (int i = 0; i < mVolumes.size(); i++) {
386 final VolumeInfo vol = mVolumes.valueAt(i);
387 final VolumeRecord rec = mRecords.get(vol.fsUuid);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700388 if (vol.isMountedWritable() && rec != null) {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700389 final long benchAge = System.currentTimeMillis() - rec.lastBenchMillis;
390 if (benchAge >= benchInterval) {
391 return true;
392 }
393 }
394 }
395 return false;
396 }
397 }
398
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700399 private CountDownLatch findOrCreateDiskScanLatch(String diskId) {
400 synchronized (mLock) {
401 CountDownLatch latch = mDiskScanLatches.get(diskId);
402 if (latch == null) {
403 latch = new CountDownLatch(1);
404 mDiskScanLatches.put(diskId, latch);
405 }
406 return latch;
407 }
408 }
409
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800410 private static String escapeNull(String arg) {
411 if (TextUtils.isEmpty(arg)) {
412 return "!";
413 } else {
414 if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
415 throw new IllegalArgumentException(arg);
416 }
417 return arg;
418 }
419 }
420
Paul Lawrence8e397362014-01-27 15:22:30 -0800421 /** List of crypto types.
422 * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
423 * corresponding commands in CommandListener.cpp */
424 public static final String[] CRYPTO_TYPES
425 = { "password", "default", "pattern", "pin" };
426
Brian Carlstrom7395a8a2014-04-28 22:11:01 -0700427 private final Context mContext;
Brian Carlstromdfad99a2014-05-07 15:21:14 -0700428 private final NativeDaemonConnector mConnector;
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700429 private final NativeDaemonConnector mCryptConnector;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700430
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700431 private volatile boolean mSystemReady = false;
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900432 private volatile boolean mBootCompleted = false;
Jeff Sharkey48877892015-03-18 11:27:19 -0700433 private volatile boolean mDaemonConnected = false;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700434
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700435 private PackageManagerService mPms;
436
437 private final Callbacks mCallbacks;
Jeff Sharkey48877892015-03-18 11:27:19 -0700438
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700439 // Two connectors - mConnector & mCryptConnector
440 private final CountDownLatch mConnectedSignal = new CountDownLatch(2);
Jeff Sharkey0be607c2012-11-14 14:39:19 -0800441 private final CountDownLatch mAsecsScanned = new CountDownLatch(1);
Jeff Sharkey48877892015-03-18 11:27:19 -0700442
443 private final Object mUnmountLock = new Object();
444 @GuardedBy("mUnmountLock")
445 private CountDownLatch mUnmountSignal;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800446
San Mehat6cdd9c02010-02-09 14:45:20 -0800447 /**
448 * Private hash of currently mounted secure containers.
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800449 * Used as a lock in methods to manipulate secure containers.
San Mehat6cdd9c02010-02-09 14:45:20 -0800450 */
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800451 final private HashSet<String> mAsecMountSet = new HashSet<String>();
San Mehat6cdd9c02010-02-09 14:45:20 -0800452
Kenny Root02c87302010-07-01 08:10:18 -0700453 /**
Kenny Root3b1abba2010-10-13 15:00:07 -0700454 * The size of the crypto algorithm key in bits for OBB files. Currently
455 * Twofish is used which takes 128-bit keys.
456 */
457 private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
458
459 /**
460 * The number of times to run SHA1 in the PBKDF2 function for OBB files.
461 * 1024 is reasonably secure and not too slow.
462 */
463 private static final int PBKDF2_HASH_ROUNDS = 1024;
464
465 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700466 * Mounted OBB tracking information. Used to track the current state of all
467 * OBBs.
Kenny Root02c87302010-07-01 08:10:18 -0700468 */
Kenny Root735de3b2010-09-30 14:11:39 -0700469 final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700470
471 /** Map from raw paths to {@link ObbState}. */
Kenny Roota02b8b02010-08-05 16:14:17 -0700472 final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
473
Svet Ganov6ee871e2015-07-10 14:29:33 -0700474 // Not guarded by a lock.
475 private final MountServiceInternalImpl mMountServiceInternal = new MountServiceInternalImpl();
476
Kenny Roota02b8b02010-08-05 16:14:17 -0700477 class ObbState implements IBinder.DeathRecipient {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700478 public ObbState(String rawPath, String canonicalPath, int callingUid,
479 IObbActionListener token, int nonce) {
480 this.rawPath = rawPath;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700481 this.canonicalPath = canonicalPath;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700482
483 this.ownerGid = UserHandle.getSharedAppGid(callingUid);
Kenny Rootaf9d6672010-10-08 09:21:39 -0700484 this.token = token;
485 this.nonce = nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700486 }
487
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700488 final String rawPath;
489 final String canonicalPath;
Kenny Roota02b8b02010-08-05 16:14:17 -0700490
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700491 final int ownerGid;
Kenny Roota02b8b02010-08-05 16:14:17 -0700492
Kenny Rootaf9d6672010-10-08 09:21:39 -0700493 // Token of remote Binder caller
494 final IObbActionListener token;
495
496 // Identifier to pass back to the token
497 final int nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700498
Kenny Root735de3b2010-09-30 14:11:39 -0700499 public IBinder getBinder() {
500 return token.asBinder();
501 }
502
Kenny Roota02b8b02010-08-05 16:14:17 -0700503 @Override
504 public void binderDied() {
505 ObbAction action = new UnmountObbAction(this, true);
506 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root735de3b2010-09-30 14:11:39 -0700507 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700508
Kenny Root5919ac62010-10-05 09:49:40 -0700509 public void link() throws RemoteException {
510 getBinder().linkToDeath(this, 0);
511 }
512
513 public void unlink() {
Kenny Root735de3b2010-09-30 14:11:39 -0700514 getBinder().unlinkToDeath(this, 0);
Kenny Roota02b8b02010-08-05 16:14:17 -0700515 }
Kenny Root38cf8862010-09-26 14:18:51 -0700516
517 @Override
518 public String toString() {
519 StringBuilder sb = new StringBuilder("ObbState{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700520 sb.append("rawPath=").append(rawPath);
521 sb.append(",canonicalPath=").append(canonicalPath);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700522 sb.append(",ownerGid=").append(ownerGid);
523 sb.append(",token=").append(token);
524 sb.append(",binder=").append(getBinder());
Kenny Root38cf8862010-09-26 14:18:51 -0700525 sb.append('}');
526 return sb.toString();
527 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700528 }
529
530 // OBB Action Handler
531 final private ObbActionHandler mObbActionHandler;
532
533 // OBB action handler messages
534 private static final int OBB_RUN_ACTION = 1;
535 private static final int OBB_MCS_BOUND = 2;
536 private static final int OBB_MCS_UNBIND = 3;
537 private static final int OBB_MCS_RECONNECT = 4;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700538 private static final int OBB_FLUSH_MOUNT_STATE = 5;
Kenny Roota02b8b02010-08-05 16:14:17 -0700539
540 /*
541 * Default Container Service information
542 */
543 static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
544 "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
545
546 final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
547
548 class DefaultContainerConnection implements ServiceConnection {
Jeff Sharkey48877892015-03-18 11:27:19 -0700549 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700550 public void onServiceConnected(ComponentName name, IBinder service) {
551 if (DEBUG_OBB)
552 Slog.i(TAG, "onServiceConnected");
553 IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
554 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
555 }
556
Jeff Sharkey48877892015-03-18 11:27:19 -0700557 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700558 public void onServiceDisconnected(ComponentName name) {
559 if (DEBUG_OBB)
560 Slog.i(TAG, "onServiceDisconnected");
561 }
562 };
563
564 // Used in the ObbActionHandler
565 private IMediaContainerService mContainerService = null;
Kenny Root02c87302010-07-01 08:10:18 -0700566
Christopher Tate7265abe2014-11-21 13:54:45 -0800567 // Last fstrim operation tracking
568 private static final String LAST_FSTRIM_FILE = "last-fstrim";
569 private final File mLastMaintenanceFile;
570 private long mLastMaintenance;
571
Kenny Root02c87302010-07-01 08:10:18 -0700572 // Handler messages
Jeff Sharkey48877892015-03-18 11:27:19 -0700573 private static final int H_SYSTEM_READY = 1;
574 private static final int H_DAEMON_CONNECTED = 2;
575 private static final int H_SHUTDOWN = 3;
576 private static final int H_FSTRIM = 4;
577 private static final int H_VOLUME_MOUNT = 5;
578 private static final int H_VOLUME_BROADCAST = 6;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700579 private static final int H_INTERNAL_BROADCAST = 7;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700580 private static final int H_VOLUME_UNMOUNT = 8;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800581 private static final int H_PARTITION_FORGET = 9;
582 private static final int H_RESET = 10;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800583
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400584 class MountServiceHandler extends Handler {
Jeff Sharkey48877892015-03-18 11:27:19 -0700585 public MountServiceHandler(Looper looper) {
586 super(looper);
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400587 }
588
Jason parks5af0b912010-11-29 09:05:25 -0600589 @Override
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800590 public void handleMessage(Message msg) {
591 switch (msg.what) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700592 case H_SYSTEM_READY: {
Jeff Sharkey48877892015-03-18 11:27:19 -0700593 handleSystemReady();
594 break;
595 }
596 case H_DAEMON_CONNECTED: {
597 handleDaemonConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700598 break;
599 }
Christopher Tated417d622013-08-19 16:14:25 -0700600 case H_FSTRIM: {
Jeff Sharkey1783f142015-04-17 10:52:51 -0700601 if (!isReady()) {
602 Slog.i(TAG, "fstrim requested, but no daemon connection yet; trying again");
Christopher Tate7618db12015-04-28 16:32:55 -0700603 sendMessageDelayed(obtainMessage(H_FSTRIM, msg.obj),
604 DateUtils.SECOND_IN_MILLIS);
605 break;
Jeff Sharkey1783f142015-04-17 10:52:51 -0700606 }
607
Christopher Tated417d622013-08-19 16:14:25 -0700608 Slog.i(TAG, "Running fstrim idle maintenance");
Christopher Tate7265abe2014-11-21 13:54:45 -0800609
610 // Remember when we kicked it off
611 try {
612 mLastMaintenance = System.currentTimeMillis();
613 mLastMaintenanceFile.setLastModified(mLastMaintenance);
614 } catch (Exception e) {
615 Slog.e(TAG, "Unable to record last fstrim!");
616 }
617
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700618 final boolean shouldBenchmark = shouldBenchmark();
Christopher Tated417d622013-08-19 16:14:25 -0700619 try {
620 // This method must be run on the main (handler) thread,
621 // so it is safe to directly call into vold.
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700622 mConnector.execute("fstrim", shouldBenchmark ? "dotrimbench" : "dotrim");
Christopher Tated417d622013-08-19 16:14:25 -0700623 } catch (NativeDaemonConnectorException ndce) {
624 Slog.e(TAG, "Failed to run fstrim!");
625 }
Christopher Tate7265abe2014-11-21 13:54:45 -0800626
Christopher Tated417d622013-08-19 16:14:25 -0700627 // invoke the completion callback, if any
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700628 // TODO: fstrim is non-blocking, so remove this useless callback
Christopher Tated417d622013-08-19 16:14:25 -0700629 Runnable callback = (Runnable) msg.obj;
630 if (callback != null) {
631 callback.run();
632 }
633 break;
634 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700635 case H_SHUTDOWN: {
636 final IMountShutdownObserver obs = (IMountShutdownObserver) msg.obj;
637 boolean success = false;
638 try {
639 success = mConnector.execute("volume", "shutdown").isClassOk();
640 } catch (NativeDaemonConnectorException ignored) {
641 }
642 if (obs != null) {
643 try {
644 obs.onShutDownComplete(success ? 0 : -1);
645 } catch (RemoteException ignored) {
646 }
647 }
648 break;
649 }
650 case H_VOLUME_MOUNT: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700651 final VolumeInfo vol = (VolumeInfo) msg.obj;
Jeff Sharkey2e606d72015-07-27 14:19:54 -0700652 if (isMountDisallowed(vol)) {
653 Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");
654 break;
655 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700656 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700657 mConnector.execute("volume", "mount", vol.id, vol.mountFlags,
658 vol.mountUserId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700659 } catch (NativeDaemonConnectorException ignored) {
660 }
661 break;
662 }
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700663 case H_VOLUME_UNMOUNT: {
664 final VolumeInfo vol = (VolumeInfo) msg.obj;
665 unmount(vol.getId());
666 break;
667 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700668 case H_VOLUME_BROADCAST: {
669 final StorageVolume userVol = (StorageVolume) msg.obj;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700670 final String envState = userVol.getState();
671 Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + envState + " to "
Jeff Sharkey48877892015-03-18 11:27:19 -0700672 + userVol.getOwner());
673
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700674 final String action = VolumeInfo.getBroadcastForEnvironment(envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700675 if (action != null) {
676 final Intent intent = new Intent(action,
677 Uri.fromFile(userVol.getPathFile()));
678 intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, userVol);
679 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
680 mContext.sendBroadcastAsUser(intent, userVol.getOwner());
681 }
682 break;
683 }
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700684 case H_INTERNAL_BROADCAST: {
685 // Internal broadcasts aimed at system components, not for
686 // third-party apps.
687 final Intent intent = (Intent) msg.obj;
688 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
689 android.Manifest.permission.WRITE_MEDIA_STORAGE);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800690 break;
691 }
692 case H_PARTITION_FORGET: {
693 final String partGuid = (String) msg.obj;
694 forgetPartition(partGuid);
695 break;
696 }
697 case H_RESET: {
698 resetIfReadyAndConnected();
699 break;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700700 }
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800701 }
702 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700703 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700704
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700705 private final Handler mHandler;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800706
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700707 private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
708 @Override
709 public void onReceive(Context context, Intent intent) {
710 final String action = intent.getAction();
711 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700712 Preconditions.checkArgument(userId >= 0);
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700713
714 try {
715 if (Intent.ACTION_USER_ADDED.equals(action)) {
716 final UserManager um = mContext.getSystemService(UserManager.class);
717 final int userSerialNumber = um.getUserSerialNumber(userId);
718 mConnector.execute("volume", "user_added", userId, userSerialNumber);
719 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700720 synchronized (mVolumes) {
721 final int size = mVolumes.size();
722 for (int i = 0; i < size; i++) {
723 final VolumeInfo vol = mVolumes.valueAt(i);
724 if (vol.mountUserId == userId) {
725 vol.mountUserId = UserHandle.USER_NULL;
726 mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
727 }
728 }
729 }
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700730 mConnector.execute("volume", "user_removed", userId);
731 }
732 } catch (NativeDaemonConnectorException e) {
733 Slog.w(TAG, "Failed to send user details to vold", e);
734 }
735 }
736 };
737
Jeff Sharkey56e62932015-03-21 20:41:00 -0700738 @Override
739 public void waitForAsecScan() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700740 waitForLatch(mAsecsScanned, "mAsecsScanned");
Kenny Root51a573c2012-05-17 13:30:28 -0700741 }
742
San Mehat207e5382010-02-04 20:46:54 -0800743 private void waitForReady() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700744 waitForLatch(mConnectedSignal, "mConnectedSignal");
Kenny Root51a573c2012-05-17 13:30:28 -0700745 }
746
Jeff Sharkey48877892015-03-18 11:27:19 -0700747 private void waitForLatch(CountDownLatch latch, String condition) {
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700748 try {
749 waitForLatch(latch, condition, -1);
750 } catch (TimeoutException ignored) {
751 }
752 }
753
754 private void waitForLatch(CountDownLatch latch, String condition, long timeoutMillis)
755 throws TimeoutException {
756 final long startMillis = SystemClock.elapsedRealtime();
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700757 while (true) {
Kenny Root51a573c2012-05-17 13:30:28 -0700758 try {
759 if (latch.await(5000, TimeUnit.MILLISECONDS)) {
San Mehat207e5382010-02-04 20:46:54 -0800760 return;
Kenny Root51a573c2012-05-17 13:30:28 -0700761 } else {
762 Slog.w(TAG, "Thread " + Thread.currentThread().getName()
Jeff Sharkey48877892015-03-18 11:27:19 -0700763 + " still waiting for " + condition + "...");
San Mehat207e5382010-02-04 20:46:54 -0800764 }
Kenny Root51a573c2012-05-17 13:30:28 -0700765 } catch (InterruptedException e) {
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700766 Slog.w(TAG, "Interrupt while waiting for " + condition);
San Mehat207e5382010-02-04 20:46:54 -0800767 }
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700768 if (timeoutMillis > 0 && SystemClock.elapsedRealtime() > startMillis + timeoutMillis) {
769 throw new TimeoutException("Thread " + Thread.currentThread().getName()
770 + " gave up waiting for " + condition + " after " + timeoutMillis + "ms");
771 }
San Mehat207e5382010-02-04 20:46:54 -0800772 }
San Mehat1f6301e2010-01-07 22:40:27 -0800773 }
Kenny Root02c87302010-07-01 08:10:18 -0700774
Paul Lawrence945490c2014-03-27 16:37:28 +0000775 private boolean isReady() {
776 try {
777 return mConnectedSignal.await(0, TimeUnit.MILLISECONDS);
778 } catch (InterruptedException e) {
779 return false;
780 }
781 }
782
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700783 private void handleSystemReady() {
Jeff Sharkey8924e872015-11-30 12:52:10 -0700784 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800785 resetIfReadyAndConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700786
Jeff Sharkey48877892015-03-18 11:27:19 -0700787 // Start scheduling nominally-daily fstrim operations
Christopher Tate115afda2014-06-06 19:06:26 -0700788 MountServiceIdler.scheduleIdlePass(mContext);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700789 }
790
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700791 /**
792 * MediaProvider has a ton of code that makes assumptions about storage
793 * paths never changing, so we outright kill them to pick up new state.
794 */
795 @Deprecated
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700796 private void killMediaProvider(List<UserInfo> users) {
797 if (users == null) return;
798
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700799 final long token = Binder.clearCallingIdentity();
800 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700801 for (UserInfo user : users) {
802 // System user does not have media provider, so skip.
803 if (user.isSystemOnly()) continue;
804
805 final ProviderInfo provider =
806 mPms.resolveContentProvider(MediaStore.AUTHORITY, 0, user.id);
807 if (provider != null) {
808 final IActivityManager am = ActivityManagerNative.getDefault();
809 try {
810 am.killApplicationWithAppId(provider.applicationInfo.packageName,
811 UserHandle.getAppId(provider.applicationInfo.uid), "vold reset");
812 // We only need to run this once. It will kill all users' media processes.
813 break;
814 } catch (RemoteException e) {
815 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700816 }
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700817 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700818 } finally {
819 Binder.restoreCallingIdentity(token);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700820 }
821 }
822
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800823 private void addInternalVolumeLocked() {
Amith Yamasania7892482015-08-07 11:09:05 -0700824 // Create a stub volume that represents internal storage
825 final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
826 VolumeInfo.TYPE_PRIVATE, null, null);
827 internal.state = VolumeInfo.STATE_MOUNTED;
828 internal.path = Environment.getDataDirectory().getAbsolutePath();
829 mVolumes.put(internal.id, internal);
830 }
831
Jeff Sharkey8924e872015-11-30 12:52:10 -0700832 private void initIfReadyAndConnected() {
833 Slog.d(TAG, "Thinking about init, mSystemReady=" + mSystemReady
834 + ", mDaemonConnected=" + mDaemonConnected);
835 if (mSystemReady && mDaemonConnected && StorageManager.isFileBasedEncryptionEnabled()) {
836 final List<UserInfo> users = mContext.getSystemService(UserManager.class)
837 .getUsers();
838 for (UserInfo user : users) {
839 try {
840 mCryptConnector.execute("cryptfs", "lock_user_key", user.id);
841 } catch (NativeDaemonConnectorException e) {
842 Slog.w(TAG, "Failed to init vold", e);
843 }
844 }
845 }
846 }
847
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800848 private void resetIfReadyAndConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700849 Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
850 + ", mDaemonConnected=" + mDaemonConnected);
851 if (mSystemReady && mDaemonConnected) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800852 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700853 killMediaProvider(users);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700854
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800855 final int[] startedUsers;
856 synchronized (mLock) {
857 startedUsers = mStartedUsers;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700858
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800859 mDisks.clear();
860 mVolumes.clear();
861
862 addInternalVolumeLocked();
863 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700864
Jeff Sharkey48877892015-03-18 11:27:19 -0700865 try {
866 mConnector.execute("volume", "reset");
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700867
868 // Tell vold about all existing and started users
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700869 for (UserInfo user : users) {
870 mConnector.execute("volume", "user_added", user.id, user.serialNumber);
871 }
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800872 for (int userId : startedUsers) {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700873 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey50a05452015-04-29 11:24:52 -0700874 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700875 } catch (NativeDaemonConnectorException e) {
876 Slog.w(TAG, "Failed to reset vold", e);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700877 }
878 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700879 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700880
Jeff Sharkey48877892015-03-18 11:27:19 -0700881 private void onStartUser(int userId) {
882 Slog.d(TAG, "onStartUser " + userId);
883
884 // We purposefully block here to make sure that user-specific
885 // staging area is ready so it's ready for zygote-forked apps to
886 // bind mount against.
887 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700888 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700889 } catch (NativeDaemonConnectorException ignored) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700890 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700891
892 // Record user as started so newly mounted volumes kick off events
893 // correctly, then synthesize events for any already-mounted volumes.
894 synchronized (mVolumes) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700895 for (int i = 0; i < mVolumes.size(); i++) {
896 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey46349872015-07-28 10:49:47 -0700897 if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700898 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey48877892015-03-18 11:27:19 -0700899 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700900
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700901 final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
902 mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700903 }
904 }
905 mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userId);
906 }
907 }
908
909 private void onCleanupUser(int userId) {
910 Slog.d(TAG, "onCleanupUser " + userId);
911
912 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700913 mConnector.execute("volume", "user_stopped", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700914 } catch (NativeDaemonConnectorException ignored) {
915 }
916
917 synchronized (mVolumes) {
918 mStartedUsers = ArrayUtils.removeInt(mStartedUsers, userId);
919 }
920 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700921
Christopher Tated417d622013-08-19 16:14:25 -0700922 void runIdleMaintenance(Runnable callback) {
923 mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
924 }
925
Christopher Tate7265abe2014-11-21 13:54:45 -0800926 // Binder entry point for kicking off an immediate fstrim
927 @Override
928 public void runMaintenance() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700929 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Christopher Tate7265abe2014-11-21 13:54:45 -0800930 runIdleMaintenance(null);
931 }
932
933 @Override
934 public long lastMaintenance() {
935 return mLastMaintenance;
936 }
937
San Mehat4270e1e2010-01-29 05:32:19 -0800938 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800939 * Callback from NativeDaemonConnector
940 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700941 @Override
San Mehat4270e1e2010-01-29 05:32:19 -0800942 public void onDaemonConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700943 mDaemonConnected = true;
944 mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();
945 }
946
947 private void handleDaemonConnected() {
Jeff Sharkey8924e872015-11-30 12:52:10 -0700948 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800949 resetIfReadyAndConnected();
Jeff Sharkey48877892015-03-18 11:27:19 -0700950
San Mehat4270e1e2010-01-29 05:32:19 -0800951 /*
Jeff Sharkey48877892015-03-18 11:27:19 -0700952 * Now that we've done our initialization, release
953 * the hounds!
San Mehat4270e1e2010-01-29 05:32:19 -0800954 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700955 mConnectedSignal.countDown();
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700956 if (mConnectedSignal.getCount() != 0) {
957 // More daemons need to connect
958 return;
959 }
Mike Lockwood7fa24aa2011-03-23 14:52:34 -0400960
Jeff Sharkey48877892015-03-18 11:27:19 -0700961 // On an encrypted device we can't see system properties yet, so pull
962 // the system locale out of the mount service.
963 if ("".equals(SystemProperties.get("vold.encrypt_progress"))) {
964 copyLocaleFromMountService();
965 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700966
Jeff Sharkey48877892015-03-18 11:27:19 -0700967 // Let package manager load internal ASECs.
968 mPms.scanAvailableAsecs();
Mike Lockwood7fa24aa2011-03-23 14:52:34 -0400969
Jeff Sharkey48877892015-03-18 11:27:19 -0700970 // Notify people waiting for ASECs to be scanned that it's done.
971 mAsecsScanned.countDown();
San Mehat4270e1e2010-01-29 05:32:19 -0800972 }
973
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700974 private void copyLocaleFromMountService() {
975 String systemLocale;
976 try {
977 systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
978 } catch (RemoteException e) {
979 return;
980 }
981 if (TextUtils.isEmpty(systemLocale)) {
982 return;
983 }
984
985 Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
986 Locale locale = Locale.forLanguageTag(systemLocale);
987 Configuration config = new Configuration();
988 config.setLocale(locale);
989 try {
990 ActivityManagerNative.getDefault().updateConfiguration(config);
991 } catch (RemoteException e) {
992 Slog.e(TAG, "Error setting system locale from mount service", e);
993 }
Elliott Hughes9c33f282014-10-13 12:39:56 -0700994
995 // Temporary workaround for http://b/17945169.
996 Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
Narayan Kamathd30dbb82015-01-15 14:48:15 +0000997 SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700998 }
999
San Mehat4270e1e2010-01-29 05:32:19 -08001000 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001001 * Callback from NativeDaemonConnector
1002 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001003 @Override
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001004 public boolean onCheckHoldWakeLock(int code) {
1005 return false;
1006 }
1007
1008 /**
1009 * Callback from NativeDaemonConnector
1010 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001011 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001012 public boolean onEvent(int code, String raw, String[] cooked) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001013 synchronized (mLock) {
1014 return onEventLocked(code, raw, cooked);
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -08001015 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001016 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001017
Jeff Sharkey48877892015-03-18 11:27:19 -07001018 private boolean onEventLocked(int code, String raw, String[] cooked) {
1019 switch (code) {
1020 case VoldResponseCode.DISK_CREATED: {
1021 if (cooked.length != 3) break;
1022 final String id = cooked[1];
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001023 int flags = Integer.parseInt(cooked[2]);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001024 if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false)
1025 || mForceAdoptable) {
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001026 flags |= DiskInfo.FLAG_ADOPTABLE;
1027 }
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001028 mDisks.put(id, new DiskInfo(id, flags));
Jeff Sharkey48877892015-03-18 11:27:19 -07001029 break;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001030 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001031 case VoldResponseCode.DISK_SIZE_CHANGED: {
1032 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001033 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001034 if (disk != null) {
1035 disk.size = Long.parseLong(cooked[2]);
San Mehat4270e1e2010-01-29 05:32:19 -08001036 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001037 break;
1038 }
1039 case VoldResponseCode.DISK_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001040 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001041 if (disk != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001042 final StringBuilder builder = new StringBuilder();
1043 for (int i = 2; i < cooked.length; i++) {
1044 builder.append(cooked[i]).append(' ');
1045 }
1046 disk.label = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001047 }
1048 break;
1049 }
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001050 case VoldResponseCode.DISK_SCANNED: {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001051 if (cooked.length != 2) break;
1052 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001053 if (disk != null) {
1054 onDiskScannedLocked(disk);
1055 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -07001056 break;
1057 }
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001058 case VoldResponseCode.DISK_SYS_PATH_CHANGED: {
1059 if (cooked.length != 3) break;
1060 final DiskInfo disk = mDisks.get(cooked[1]);
1061 if (disk != null) {
1062 disk.sysPath = cooked[2];
1063 }
1064 break;
1065 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001066 case VoldResponseCode.DISK_DESTROYED: {
1067 if (cooked.length != 2) break;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07001068 final DiskInfo disk = mDisks.remove(cooked[1]);
1069 if (disk != null) {
1070 mCallbacks.notifyDiskDestroyed(disk);
1071 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001072 break;
1073 }
San Mehat4270e1e2010-01-29 05:32:19 -08001074
Jeff Sharkey48877892015-03-18 11:27:19 -07001075 case VoldResponseCode.VOLUME_CREATED: {
Jeff Sharkey48877892015-03-18 11:27:19 -07001076 final String id = cooked[1];
1077 final int type = Integer.parseInt(cooked[2]);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001078 final String diskId = TextUtils.nullIfEmpty(cooked[3]);
1079 final String partGuid = TextUtils.nullIfEmpty(cooked[4]);
1080
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001081 final DiskInfo disk = mDisks.get(diskId);
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07001082 final VolumeInfo vol = new VolumeInfo(id, type, disk, partGuid);
Jeff Sharkey48877892015-03-18 11:27:19 -07001083 mVolumes.put(id, vol);
1084 onVolumeCreatedLocked(vol);
1085 break;
1086 }
1087 case VoldResponseCode.VOLUME_STATE_CHANGED: {
1088 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001089 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001090 if (vol != null) {
1091 final int oldState = vol.state;
1092 final int newState = Integer.parseInt(cooked[2]);
1093 vol.state = newState;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001094 onVolumeStateChangedLocked(vol, oldState, newState);
Jeff Sharkey48877892015-03-18 11:27:19 -07001095 }
1096 break;
1097 }
1098 case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: {
1099 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001100 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001101 if (vol != null) {
1102 vol.fsType = cooked[2];
1103 }
1104 break;
1105 }
1106 case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
1107 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001108 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001109 if (vol != null) {
1110 vol.fsUuid = cooked[2];
1111 }
1112 break;
1113 }
1114 case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001115 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001116 if (vol != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001117 final StringBuilder builder = new StringBuilder();
1118 for (int i = 2; i < cooked.length; i++) {
1119 builder.append(cooked[i]).append(' ');
1120 }
1121 vol.fsLabel = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001122 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001123 // TODO: notify listeners that label changed
Jeff Sharkey48877892015-03-18 11:27:19 -07001124 break;
1125 }
1126 case VoldResponseCode.VOLUME_PATH_CHANGED: {
1127 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001128 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001129 if (vol != null) {
1130 vol.path = cooked[2];
1131 }
1132 break;
1133 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001134 case VoldResponseCode.VOLUME_INTERNAL_PATH_CHANGED: {
1135 if (cooked.length != 3) break;
1136 final VolumeInfo vol = mVolumes.get(cooked[1]);
1137 if (vol != null) {
1138 vol.internalPath = cooked[2];
1139 }
1140 break;
1141 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001142 case VoldResponseCode.VOLUME_DESTROYED: {
1143 if (cooked.length != 2) break;
1144 mVolumes.remove(cooked[1]);
1145 break;
1146 }
San Mehat4270e1e2010-01-29 05:32:19 -08001147
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001148 case VoldResponseCode.MOVE_STATUS: {
1149 final int status = Integer.parseInt(cooked[1]);
1150 onMoveStatusLocked(status);
1151 break;
1152 }
Jeff Sharkey9756d752015-05-14 21:07:42 -07001153 case VoldResponseCode.BENCHMARK_RESULT: {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001154 if (cooked.length != 7) break;
1155 final String path = cooked[1];
1156 final String ident = cooked[2];
1157 final long create = Long.parseLong(cooked[3]);
1158 final long drop = Long.parseLong(cooked[4]);
1159 final long run = Long.parseLong(cooked[5]);
1160 final long destroy = Long.parseLong(cooked[6]);
1161
Jeff Sharkey9756d752015-05-14 21:07:42 -07001162 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001163 dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
1164 + " " + ident + " " + create + " " + run + " " + destroy);
1165
1166 final VolumeRecord rec = findRecordForPath(path);
1167 if (rec != null) {
1168 rec.lastBenchMillis = System.currentTimeMillis();
1169 writeSettingsLocked();
1170 }
1171
1172 break;
1173 }
1174 case VoldResponseCode.TRIM_RESULT: {
1175 if (cooked.length != 4) break;
1176 final String path = cooked[1];
1177 final long bytes = Long.parseLong(cooked[2]);
1178 final long time = Long.parseLong(cooked[3]);
1179
1180 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
1181 dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path)
1182 + " " + bytes + " " + time);
1183
1184 final VolumeRecord rec = findRecordForPath(path);
1185 if (rec != null) {
1186 rec.lastTrimMillis = System.currentTimeMillis();
1187 writeSettingsLocked();
1188 }
1189
Jeff Sharkey9756d752015-05-14 21:07:42 -07001190 break;
1191 }
1192
Jeff Sharkey48877892015-03-18 11:27:19 -07001193 default: {
1194 Slog.d(TAG, "Unhandled vold event " + code);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001195 }
San Mehat4270e1e2010-01-29 05:32:19 -08001196 }
1197
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001198 return true;
San Mehat4270e1e2010-01-29 05:32:19 -08001199 }
1200
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001201 private void onDiskScannedLocked(DiskInfo disk) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001202 int volumeCount = 0;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001203 for (int i = 0; i < mVolumes.size(); i++) {
1204 final VolumeInfo vol = mVolumes.valueAt(i);
1205 if (Objects.equals(disk.id, vol.getDiskId())) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001206 volumeCount++;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001207 }
1208 }
1209
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001210 final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
1211 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1212 intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
1213 intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001214 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001215
1216 final CountDownLatch latch = mDiskScanLatches.remove(disk.id);
1217 if (latch != null) {
1218 latch.countDown();
1219 }
1220
Jeff Sharkeyf5a6bd72015-05-19 14:42:38 -07001221 disk.volumeCount = volumeCount;
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001222 mCallbacks.notifyDiskScanned(disk, volumeCount);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001223 }
1224
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001225 private void onVolumeCreatedLocked(VolumeInfo vol) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001226 if (vol.type == VolumeInfo.TYPE_EMULATED) {
1227 final StorageManager storage = mContext.getSystemService(StorageManager.class);
1228 final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
1229
1230 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
1231 && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
1232 Slog.v(TAG, "Found primary storage at " + vol);
1233 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1234 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1235 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1236
1237 } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
1238 Slog.v(TAG, "Found primary storage at " + vol);
1239 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1240 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1241 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1242 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001243
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001244 } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001245 // TODO: only look at first public partition
1246 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1247 && vol.disk.isDefaultPrimary()) {
1248 Slog.v(TAG, "Found primary storage at " + vol);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001249 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1250 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
San Mehat4270e1e2010-01-29 05:32:19 -08001251 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001252
1253 // Adoptable public disks are visible to apps, since they meet
1254 // public API requirement of being in a stable location.
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001255 if (vol.disk.isAdoptable()) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001256 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1257 }
1258
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07001259 vol.mountUserId = ActivityManager.getCurrentUser();
Jeff Sharkey48877892015-03-18 11:27:19 -07001260 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001261
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001262 } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1263 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1264
San Mehat4270e1e2010-01-29 05:32:19 -08001265 } else {
Jeff Sharkey48877892015-03-18 11:27:19 -07001266 Slog.d(TAG, "Skipping automatic mounting of " + vol);
San Mehat4270e1e2010-01-29 05:32:19 -08001267 }
1268 }
1269
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001270 private boolean isBroadcastWorthy(VolumeInfo vol) {
1271 switch (vol.getType()) {
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001272 case VolumeInfo.TYPE_PRIVATE:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001273 case VolumeInfo.TYPE_PUBLIC:
1274 case VolumeInfo.TYPE_EMULATED:
1275 break;
1276 default:
1277 return false;
1278 }
1279
1280 switch (vol.getState()) {
1281 case VolumeInfo.STATE_MOUNTED:
1282 case VolumeInfo.STATE_MOUNTED_READ_ONLY:
1283 case VolumeInfo.STATE_EJECTING:
1284 case VolumeInfo.STATE_UNMOUNTED:
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001285 case VolumeInfo.STATE_UNMOUNTABLE:
Tony Mantlerf0d71052015-06-24 11:45:25 -07001286 case VolumeInfo.STATE_BAD_REMOVAL:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001287 break;
1288 default:
1289 return false;
1290 }
1291
1292 return true;
1293 }
1294
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001295 private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001296 // Remember that we saw this volume so we're ready to accept user
1297 // metadata, or so we can annoy them when a private volume is ejected
1298 if (vol.isMountedReadable() && !TextUtils.isEmpty(vol.fsUuid)) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001299 VolumeRecord rec = mRecords.get(vol.fsUuid);
1300 if (rec == null) {
1301 rec = new VolumeRecord(vol.type, vol.fsUuid);
1302 rec.partGuid = vol.partGuid;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001303 rec.createdMillis = System.currentTimeMillis();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001304 if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1305 rec.nickname = vol.disk.getDescription();
1306 }
1307 mRecords.put(rec.fsUuid, rec);
1308 writeSettingsLocked();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001309 } else {
1310 // Handle upgrade case where we didn't store partition GUID
1311 if (TextUtils.isEmpty(rec.partGuid)) {
1312 rec.partGuid = vol.partGuid;
1313 writeSettingsLocked();
1314 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001315 }
1316 }
1317
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001318 mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
1319
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001320 // Do not broadcast before boot has completed to avoid launching the
1321 // processes that receive the intent unnecessarily.
1322 if (mBootCompleted && isBroadcastWorthy(vol)) {
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001323 final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001324 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
1325 intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
Tony Mantlerf0d71052015-06-24 11:45:25 -07001326 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001327 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001328 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001329 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001330
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001331 final String oldStateEnv = VolumeInfo.getEnvironmentForState(oldState);
1332 final String newStateEnv = VolumeInfo.getEnvironmentForState(newState);
Emily Bernier92aa5a22014-07-07 10:11:48 -04001333
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001334 if (!Objects.equals(oldStateEnv, newStateEnv)) {
1335 // Kick state changed event towards all started users. Any users
1336 // started after this point will trigger additional
1337 // user-specific broadcasts.
1338 for (int userId : mStartedUsers) {
Jeff Sharkey46349872015-07-28 10:49:47 -07001339 if (vol.isVisibleForRead(userId)) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001340 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001341 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey48877892015-03-18 11:27:19 -07001342
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001343 mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
1344 newStateEnv);
San Mehat4270e1e2010-01-29 05:32:19 -08001345 }
1346 }
1347 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001348
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001349 if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.state == VolumeInfo.STATE_EJECTING) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001350 // TODO: this should eventually be handled by new ObbVolume state changes
1351 /*
1352 * Some OBBs might have been unmounted when this volume was
1353 * unmounted, so send a message to the handler to let it know to
1354 * remove those from the list of mounted OBBS.
1355 */
1356 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
1357 OBB_FLUSH_MOUNT_STATE, vol.path));
1358 }
San Mehat4270e1e2010-01-29 05:32:19 -08001359 }
1360
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001361 private void onMoveStatusLocked(int status) {
1362 if (mMoveCallback == null) {
1363 Slog.w(TAG, "Odd, status but no move requested");
1364 return;
1365 }
1366
1367 // TODO: estimate remaining time
1368 try {
Jeff Sharkey50a05452015-04-29 11:24:52 -07001369 mMoveCallback.onStatusChanged(-1, status, -1);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001370 } catch (RemoteException ignored) {
1371 }
1372
1373 // We've finished copying and we're about to clean up old data, so
1374 // remember that move was successful if we get rebooted
1375 if (status == MOVE_STATUS_COPY_FINISHED) {
1376 Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
1377
1378 mPrimaryStorageUuid = mMoveTargetUuid;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001379 writeSettingsLocked();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001380 }
1381
1382 if (PackageManager.isMoveStatusFinished(status)) {
1383 Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status);
1384
1385 mMoveCallback = null;
1386 mMoveTargetUuid = null;
1387 }
1388 }
1389
Jeff Sharkey48877892015-03-18 11:27:19 -07001390 private void enforcePermission(String perm) {
1391 mContext.enforceCallingOrSelfPermission(perm, perm);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001392 }
1393
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001394 /**
1395 * Decide if volume is mountable per device policies.
1396 */
1397 private boolean isMountDisallowed(VolumeInfo vol) {
1398 if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
1399 final UserManager userManager = mContext.getSystemService(UserManager.class);
1400 return userManager.hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
1401 Binder.getCallingUserHandle());
1402 } else {
1403 return false;
Emily Bernier92aa5a22014-07-07 10:11:48 -04001404 }
1405 }
1406
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001407 private void enforceAdminUser() {
1408 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1409 final int callingUserId = UserHandle.getCallingUserId();
1410 boolean isAdmin;
1411 long token = Binder.clearCallingIdentity();
1412 try {
1413 isAdmin = um.getUserInfo(callingUserId).isAdmin();
1414 } finally {
1415 Binder.restoreCallingIdentity(token);
1416 }
1417 if (!isAdmin) {
1418 throw new SecurityException("Only admin users can adopt sd cards");
1419 }
1420 }
1421
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001422 /**
San Mehat207e5382010-02-04 20:46:54 -08001423 * Constructs a new MountService instance
1424 *
1425 * @param context Binder context for this service
1426 */
1427 public MountService(Context context) {
Christopher Tated417d622013-08-19 16:14:25 -07001428 sSelf = this;
1429
San Mehat207e5382010-02-04 20:46:54 -08001430 mContext = context;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001431 mCallbacks = new Callbacks(FgThread.get().getLooper());
San Mehat207e5382010-02-04 20:46:54 -08001432
San Mehat207e5382010-02-04 20:46:54 -08001433 // XXX: This will go away soon in favor of IMountServiceObserver
1434 mPms = (PackageManagerService) ServiceManager.getService("package");
1435
Dianne Hackbornefa92b22013-05-03 14:11:43 -07001436 HandlerThread hthread = new HandlerThread(TAG);
1437 hthread.start();
1438 mHandler = new MountServiceHandler(hthread.getLooper());
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001439
Kenny Roota02b8b02010-08-05 16:14:17 -07001440 // Add OBB Action Handler to MountService thread.
Dianne Hackborn8d044e82013-04-30 17:24:15 -07001441 mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
Kenny Roota02b8b02010-08-05 16:14:17 -07001442
Christopher Tate7265abe2014-11-21 13:54:45 -08001443 // Initialize the last-fstrim tracking if necessary
1444 File dataDir = Environment.getDataDirectory();
1445 File systemDir = new File(dataDir, "system");
1446 mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
1447 if (!mLastMaintenanceFile.exists()) {
1448 // Not setting mLastMaintenance here means that we will force an
1449 // fstrim during reboot following the OTA that installs this code.
1450 try {
1451 (new FileOutputStream(mLastMaintenanceFile)).close();
1452 } catch (IOException e) {
1453 Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
1454 }
1455 } else {
1456 mLastMaintenance = mLastMaintenanceFile.lastModified();
1457 }
1458
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001459 mSettingsFile = new AtomicFile(
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001460 new File(Environment.getSystemSecureDirectory(), "storage.xml"));
1461
1462 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001463 readSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001464 }
1465
Svet Ganov6ee871e2015-07-10 14:29:33 -07001466 LocalServices.addService(MountServiceInternal.class, mMountServiceInternal);
1467
Marco Nelissenc34ebce2010-02-18 13:39:41 -08001468 /*
Kenny Root305bcbf2010-09-03 07:56:38 -07001469 * Create the connection to vold with a maximum queue of twice the
1470 * amount of containers we'd ever expect to have. This keeps an
1471 * "asec list" from blocking a thread repeatedly.
1472 */
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001473
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001474 mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
1475 null);
Jeff Sharkey48877892015-03-18 11:27:19 -07001476 mConnector.setDebug(true);
Jeff Sharkey8948c012015-11-03 12:33:54 -08001477 mConnector.setWarnIfHeld(mLock);
Kenny Root51a573c2012-05-17 13:30:28 -07001478
Kenny Root305bcbf2010-09-03 07:56:38 -07001479 Thread thread = new Thread(mConnector, VOLD_TAG);
San Mehat207e5382010-02-04 20:46:54 -08001480 thread.start();
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07001481
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001482 // Reuse parameters from first connector since they are tested and safe
1483 mCryptConnector = new NativeDaemonConnector(this, "cryptd",
1484 MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
1485 mCryptConnector.setDebug(true);
1486
1487 Thread crypt_thread = new Thread(mCryptConnector, CRYPTD_TAG);
1488 crypt_thread.start();
1489
Jeff Sharkeybcd262d2015-06-10 09:41:17 -07001490 final IntentFilter userFilter = new IntentFilter();
1491 userFilter.addAction(Intent.ACTION_USER_ADDED);
1492 userFilter.addAction(Intent.ACTION_USER_REMOVED);
1493 mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
1494
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001495 synchronized (mLock) {
1496 addInternalVolumeLocked();
1497 }
Amith Yamasania7892482015-08-07 11:09:05 -07001498
Kenny Root07714d42011-08-17 17:49:28 -07001499 // Add ourself to the Watchdog monitors if enabled.
1500 if (WATCHDOG_ENABLE) {
1501 Watchdog.getInstance().addMonitor(this);
1502 }
San Mehat207e5382010-02-04 20:46:54 -08001503 }
1504
Jeff Sharkey56e62932015-03-21 20:41:00 -07001505 private void systemReady() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001506 mSystemReady = true;
1507 mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
1508 }
1509
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001510 private void bootCompleted() {
1511 mBootCompleted = true;
1512 }
1513
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001514 private String getDefaultPrimaryStorageUuid() {
1515 if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) {
1516 return StorageManager.UUID_PRIMARY_PHYSICAL;
1517 } else {
1518 return StorageManager.UUID_PRIVATE_INTERNAL;
1519 }
1520 }
1521
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001522 private void readSettingsLocked() {
1523 mRecords.clear();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001524 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001525 mForceAdoptable = false;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001526
1527 FileInputStream fis = null;
1528 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001529 fis = mSettingsFile.openRead();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001530 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001531 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001532
1533 int type;
1534 while ((type = in.next()) != END_DOCUMENT) {
1535 if (type == START_TAG) {
1536 final String tag = in.getName();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001537 if (TAG_VOLUMES.equals(tag)) {
1538 final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001539 final boolean primaryPhysical = SystemProperties.getBoolean(
1540 StorageManager.PROP_PRIMARY_PHYSICAL, false);
1541 final boolean validAttr = (version >= VERSION_FIX_PRIMARY)
1542 || (version >= VERSION_ADD_PRIMARY && !primaryPhysical);
1543 if (validAttr) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001544 mPrimaryStorageUuid = readStringAttribute(in,
1545 ATTR_PRIMARY_STORAGE_UUID);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001546 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001547 mForceAdoptable = readBooleanAttribute(in, ATTR_FORCE_ADOPTABLE, false);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001548
1549 } else if (TAG_VOLUME.equals(tag)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001550 final VolumeRecord rec = readVolumeRecord(in);
1551 mRecords.put(rec.fsUuid, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001552 }
1553 }
1554 }
1555 } catch (FileNotFoundException e) {
1556 // Missing metadata is okay, probably first boot
1557 } catch (IOException e) {
1558 Slog.wtf(TAG, "Failed reading metadata", e);
1559 } catch (XmlPullParserException e) {
1560 Slog.wtf(TAG, "Failed reading metadata", e);
1561 } finally {
1562 IoUtils.closeQuietly(fis);
1563 }
1564 }
1565
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001566 private void writeSettingsLocked() {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001567 FileOutputStream fos = null;
1568 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001569 fos = mSettingsFile.startWrite();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001570
1571 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001572 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001573 out.startDocument(null, true);
1574 out.startTag(null, TAG_VOLUMES);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001575 writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001576 writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001577 writeBooleanAttribute(out, ATTR_FORCE_ADOPTABLE, mForceAdoptable);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001578 final int size = mRecords.size();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001579 for (int i = 0; i < size; i++) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001580 final VolumeRecord rec = mRecords.valueAt(i);
1581 writeVolumeRecord(out, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001582 }
1583 out.endTag(null, TAG_VOLUMES);
1584 out.endDocument();
1585
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001586 mSettingsFile.finishWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001587 } catch (IOException e) {
1588 if (fos != null) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001589 mSettingsFile.failWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001590 }
1591 }
1592 }
1593
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001594 public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
1595 final int type = readIntAttribute(in, ATTR_TYPE);
1596 final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
1597 final VolumeRecord meta = new VolumeRecord(type, fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001598 meta.partGuid = readStringAttribute(in, ATTR_PART_GUID);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001599 meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
1600 meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001601 meta.createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
1602 meta.lastTrimMillis = readLongAttribute(in, ATTR_LAST_TRIM_MILLIS);
1603 meta.lastBenchMillis = readLongAttribute(in, ATTR_LAST_BENCH_MILLIS);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001604 return meta;
1605 }
1606
1607 public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
1608 out.startTag(null, TAG_VOLUME);
1609 writeIntAttribute(out, ATTR_TYPE, rec.type);
1610 writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001611 writeStringAttribute(out, ATTR_PART_GUID, rec.partGuid);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001612 writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
1613 writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001614 writeLongAttribute(out, ATTR_CREATED_MILLIS, rec.createdMillis);
1615 writeLongAttribute(out, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
1616 writeLongAttribute(out, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001617 out.endTag(null, TAG_VOLUME);
1618 }
1619
San Mehat207e5382010-02-04 20:46:54 -08001620 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001621 * Exposed API calls below here
1622 */
1623
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001624 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001625 public void registerListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001626 mCallbacks.register(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001627 }
1628
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001629 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001630 public void unregisterListener(IMountServiceListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001631 mCallbacks.unregister(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001632 }
1633
Jeff Sharkey48877892015-03-18 11:27:19 -07001634 @Override
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -08001635 public void shutdown(final IMountShutdownObserver observer) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001636 enforcePermission(android.Manifest.permission.SHUTDOWN);
San Mehat4270e1e2010-01-29 05:32:19 -08001637
San Mehata5078592010-03-25 09:36:54 -07001638 Slog.i(TAG, "Shutting down");
Jeff Sharkey48877892015-03-18 11:27:19 -07001639 mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001640 }
1641
Jeff Sharkey48877892015-03-18 11:27:19 -07001642 @Override
San Mehatb1043402010-02-05 08:26:50 -08001643 public boolean isUsbMassStorageConnected() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001644 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001645 }
1646
Jeff Sharkey48877892015-03-18 11:27:19 -07001647 @Override
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -08001648 public void setUsbMassStorageEnabled(boolean enable) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001649 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001650 }
1651
Jeff Sharkey48877892015-03-18 11:27:19 -07001652 @Override
San Mehatb1043402010-02-05 08:26:50 -08001653 public boolean isUsbMassStorageEnabled() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001654 throw new UnsupportedOperationException();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655 }
Jason parks9ed98bc2011-01-17 09:58:35 -06001656
Jeff Sharkey48877892015-03-18 11:27:19 -07001657 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001658 public String getVolumeState(String mountPoint) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001659 throw new UnsupportedOperationException();
San Mehat7fd0fee2009-12-17 07:12:23 -08001660 }
1661
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001662 @Override
Kenny Roote1ff2142010-10-12 11:20:01 -07001663 public boolean isExternalStorageEmulated() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001664 throw new UnsupportedOperationException();
Kenny Roote1ff2142010-10-12 11:20:01 -07001665 }
1666
Jeff Sharkey48877892015-03-18 11:27:19 -07001667 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001668 public int mountVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001669 mount(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001670 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 }
1672
Jeff Sharkey48877892015-03-18 11:27:19 -07001673 @Override
Ben Komalo13c71972011-09-07 16:35:56 -07001674 public void unmountVolume(String path, boolean force, boolean removeEncryption) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001675 unmount(findVolumeIdForPathOrThrow(path));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676 }
1677
Jeff Sharkey48877892015-03-18 11:27:19 -07001678 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001679 public int formatVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001680 format(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001681 return 0;
1682 }
1683
1684 @Override
1685 public void mount(String volId) {
1686 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1687 waitForReady();
1688
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001689 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001690 if (isMountDisallowed(vol)) {
1691 throw new SecurityException("Mounting " + volId + " restricted by policy");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001692 }
1693 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001694 mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001695 } catch (NativeDaemonConnectorException e) {
1696 throw e.rethrowAsParcelableException();
1697 }
1698 }
1699
1700 @Override
1701 public void unmount(String volId) {
1702 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1703 waitForReady();
1704
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001705 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001706
1707 // TODO: expand PMS to know about multiple volumes
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001708 if (vol.isPrimaryPhysical()) {
1709 final long ident = Binder.clearCallingIdentity();
1710 try {
1711 synchronized (mUnmountLock) {
1712 mUnmountSignal = new CountDownLatch(1);
1713 mPms.updateExternalMediaStatus(false, true);
1714 waitForLatch(mUnmountSignal, "mUnmountSignal");
1715 mUnmountSignal = null;
1716 }
1717 } finally {
1718 Binder.restoreCallingIdentity(ident);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001719 }
1720 }
1721
1722 try {
1723 mConnector.execute("volume", "unmount", vol.id);
1724 } catch (NativeDaemonConnectorException e) {
1725 throw e.rethrowAsParcelableException();
1726 }
1727 }
1728
1729 @Override
1730 public void format(String volId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001731 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -08001732 waitForReady();
San Mehat5b77dab2010-01-26 13:28:50 -08001733
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001734 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001735 try {
Jeff Sharkey4e83cc92015-05-27 14:38:39 -07001736 mConnector.execute("volume", "format", vol.id, "auto");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001737 } catch (NativeDaemonConnectorException e) {
1738 throw e.rethrowAsParcelableException();
Jeff Sharkey48877892015-03-18 11:27:19 -07001739 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001740 }
1741
1742 @Override
Jeff Sharkey9756d752015-05-14 21:07:42 -07001743 public long benchmark(String volId) {
1744 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1745 waitForReady();
1746
1747 try {
Jeff Sharkey14cbe522015-07-08 14:06:37 -07001748 // TODO: make benchmark async so we don't block other commands
1749 final NativeDaemonEvent res = mConnector.execute(3 * DateUtils.MINUTE_IN_MILLIS,
1750 "volume", "benchmark", volId);
Jeff Sharkey9756d752015-05-14 21:07:42 -07001751 return Long.parseLong(res.getMessage());
Todd Kennedy8101ee62015-06-23 13:35:28 -07001752 } catch (NativeDaemonTimeoutException e) {
1753 return Long.MAX_VALUE;
Jeff Sharkey9756d752015-05-14 21:07:42 -07001754 } catch (NativeDaemonConnectorException e) {
1755 throw e.rethrowAsParcelableException();
1756 }
1757 }
1758
1759 @Override
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001760 public void partitionPublic(String diskId) {
1761 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1762 waitForReady();
1763
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001764 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001765 try {
1766 mConnector.execute("volume", "partition", diskId, "public");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001767 waitForLatch(latch, "partitionPublic", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001768 } catch (NativeDaemonConnectorException e) {
1769 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001770 } catch (TimeoutException e) {
1771 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001772 }
1773 }
1774
1775 @Override
1776 public void partitionPrivate(String diskId) {
1777 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001778 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001779 waitForReady();
1780
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001781 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001782 try {
1783 mConnector.execute("volume", "partition", diskId, "private");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001784 waitForLatch(latch, "partitionPrivate", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001785 } catch (NativeDaemonConnectorException e) {
1786 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001787 } catch (TimeoutException e) {
1788 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001789 }
1790 }
1791
1792 @Override
1793 public void partitionMixed(String diskId, int ratio) {
1794 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001795 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001796 waitForReady();
1797
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001798 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001799 try {
1800 mConnector.execute("volume", "partition", diskId, "mixed", ratio);
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001801 waitForLatch(latch, "partitionMixed", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001802 } catch (NativeDaemonConnectorException e) {
1803 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001804 } catch (TimeoutException e) {
1805 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001806 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001807 }
1808
Jeff Sharkey48877892015-03-18 11:27:19 -07001809 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001810 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001811 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1812 waitForReady();
1813
Jeff Sharkey50a05452015-04-29 11:24:52 -07001814 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001815 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001816 final VolumeRecord rec = mRecords.get(fsUuid);
1817 rec.nickname = nickname;
Jeff Sharkey50a05452015-04-29 11:24:52 -07001818 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001819 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001820 }
1821 }
1822
1823 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001824 public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001825 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1826 waitForReady();
1827
Jeff Sharkey50a05452015-04-29 11:24:52 -07001828 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001829 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001830 final VolumeRecord rec = mRecords.get(fsUuid);
1831 rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001832 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001833 writeSettingsLocked();
1834 }
1835 }
1836
1837 @Override
1838 public void forgetVolume(String fsUuid) {
1839 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1840 waitForReady();
1841
Jeff Sharkey50a05452015-04-29 11:24:52 -07001842 Preconditions.checkNotNull(fsUuid);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001843
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001844 synchronized (mLock) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001845 final VolumeRecord rec = mRecords.remove(fsUuid);
1846 if (rec != null && !TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001847 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001848 }
1849 mCallbacks.notifyVolumeForgotten(fsUuid);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001850
1851 // If this had been primary storage, revert back to internal and
1852 // reset vold so we bind into new volume into place.
1853 if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001854 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001855 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001856 }
1857
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001858 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001859 }
1860 }
1861
Jeff Sharkey7d2af542015-05-12 15:27:15 -07001862 @Override
1863 public void forgetAllVolumes() {
1864 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1865 waitForReady();
1866
Jeff Sharkey50a05452015-04-29 11:24:52 -07001867 synchronized (mLock) {
1868 for (int i = 0; i < mRecords.size(); i++) {
1869 final String fsUuid = mRecords.keyAt(i);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001870 final VolumeRecord rec = mRecords.valueAt(i);
1871 if (!TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001872 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001873 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001874 mCallbacks.notifyVolumeForgotten(fsUuid);
1875 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001876 mRecords.clear();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001877
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001878 if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)) {
1879 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
1880 }
1881
1882 writeSettingsLocked();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001883 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001884 }
1885 }
1886
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001887 private void forgetPartition(String partGuid) {
1888 try {
1889 mConnector.execute("volume", "forget_partition", partGuid);
1890 } catch (NativeDaemonConnectorException e) {
1891 Slog.w(TAG, "Failed to forget key for " + partGuid + ": " + e);
1892 }
1893 }
1894
Svet Ganov6ee871e2015-07-10 14:29:33 -07001895 private void remountUidExternalStorage(int uid, int mode) {
Jeff Sharkey9527b222015-06-24 15:24:48 -07001896 waitForReady();
1897
Svet Ganov6ee871e2015-07-10 14:29:33 -07001898 String modeName = "none";
1899 switch (mode) {
1900 case Zygote.MOUNT_EXTERNAL_DEFAULT: {
1901 modeName = "default";
1902 } break;
1903
1904 case Zygote.MOUNT_EXTERNAL_READ: {
1905 modeName = "read";
1906 } break;
1907
1908 case Zygote.MOUNT_EXTERNAL_WRITE: {
1909 modeName = "write";
1910 } break;
Jeff Sharkey9527b222015-06-24 15:24:48 -07001911 }
1912
1913 try {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001914 mConnector.execute("volume", "remount_uid", uid, modeName);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001915 } catch (NativeDaemonConnectorException e) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001916 Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001917 }
1918 }
1919
1920 @Override
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001921 public void setDebugFlags(int flags, int mask) {
1922 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1923 waitForReady();
1924
Jeff Sharkeyba512352015-11-12 20:17:45 -08001925 if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
1926 final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
1927 SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
1928 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001929
Jeff Sharkeyba512352015-11-12 20:17:45 -08001930 if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
1931 synchronized (mLock) {
1932 mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
1933
1934 writeSettingsLocked();
1935 mHandler.obtainMessage(H_RESET).sendToTarget();
1936 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001937 }
1938 }
1939
1940 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001941 public String getPrimaryStorageUuid() {
1942 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1943 waitForReady();
1944
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001945 synchronized (mLock) {
1946 return mPrimaryStorageUuid;
1947 }
1948 }
1949
1950 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001951 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
1952 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1953 waitForReady();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001954
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001955 synchronized (mLock) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001956 if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) {
1957 throw new IllegalArgumentException("Primary storage already at " + volumeUuid);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001958 }
1959
1960 if (mMoveCallback != null) {
1961 throw new IllegalStateException("Move already in progress");
1962 }
1963 mMoveCallback = callback;
1964 mMoveTargetUuid = volumeUuid;
1965
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001966 // When moving to/from primary physical volume, we probably just nuked
1967 // the current storage location, so we have nothing to move.
1968 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1969 || Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
1970 Slog.d(TAG, "Skipping move to/from primary physical");
1971 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
1972 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001973 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001974
1975 } else {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001976 final VolumeInfo from = findStorageForUuid(mPrimaryStorageUuid);
1977 final VolumeInfo to = findStorageForUuid(volumeUuid);
1978
1979 if (from == null) {
1980 Slog.w(TAG, "Failing move due to missing from volume " + mPrimaryStorageUuid);
1981 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
1982 return;
1983 } else if (to == null) {
1984 Slog.w(TAG, "Failing move due to missing to volume " + volumeUuid);
1985 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
1986 return;
1987 }
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001988
1989 try {
1990 mConnector.execute("volume", "move_storage", from.id, to.id);
1991 } catch (NativeDaemonConnectorException e) {
1992 throw e.rethrowAsParcelableException();
1993 }
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001994 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001995 }
1996 }
1997
1998 @Override
Mike Lockwoodecedfdc2011-06-08 15:11:59 -07001999 public int[] getStorageUsers(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002000 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehatc1b4ce92010-02-16 17:13:03 -08002001 waitForReady();
2002 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002003 final String[] r = NativeDaemonEvent.filterMessageList(
2004 mConnector.executeForList("storage", "users", path),
2005 VoldResponseCode.StorageUsersListResult);
2006
San Mehatc1b4ce92010-02-16 17:13:03 -08002007 // FMT: <pid> <process name>
2008 int[] data = new int[r.length];
2009 for (int i = 0; i < r.length; i++) {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002010 String[] tok = r[i].split(" ");
San Mehatc1b4ce92010-02-16 17:13:03 -08002011 try {
2012 data[i] = Integer.parseInt(tok[0]);
2013 } catch (NumberFormatException nfe) {
San Mehata5078592010-03-25 09:36:54 -07002014 Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
San Mehatc1b4ce92010-02-16 17:13:03 -08002015 return new int[0];
2016 }
2017 }
2018 return data;
2019 } catch (NativeDaemonConnectorException e) {
San Mehata5078592010-03-25 09:36:54 -07002020 Slog.e(TAG, "Failed to retrieve storage users list", e);
San Mehatc1b4ce92010-02-16 17:13:03 -08002021 return new int[0];
2022 }
2023 }
2024
San Mehatb1043402010-02-05 08:26:50 -08002025 private void warnOnNotMounted() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002026 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002027 for (int i = 0; i < mVolumes.size(); i++) {
2028 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07002029 if (vol.isPrimary() && vol.isMountedWritable()) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002030 // Cool beans, we have a mounted primary volume
2031 return;
2032 }
Jeff Sharkey32ee8312012-09-30 13:21:31 -07002033 }
San Mehatb1043402010-02-05 08:26:50 -08002034 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002035
2036 Slog.w(TAG, "No primary storage mounted!");
San Mehatb1043402010-02-05 08:26:50 -08002037 }
2038
San Mehat4270e1e2010-01-29 05:32:19 -08002039 public String[] getSecureContainerList() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002040 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002041 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002042 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002043
San Mehat4270e1e2010-01-29 05:32:19 -08002044 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002045 return NativeDaemonEvent.filterMessageList(
2046 mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
San Mehat4270e1e2010-01-29 05:32:19 -08002047 } catch (NativeDaemonConnectorException e) {
2048 return new String[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002049 }
2050 }
San Mehat36972292010-01-06 11:06:32 -08002051
Kenny Root6dceb882012-04-12 14:23:49 -07002052 public int createSecureContainer(String id, int sizeMb, String fstype, String key,
2053 int ownerUid, boolean external) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002054 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehat207e5382010-02-04 20:46:54 -08002055 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002056 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002057
San Mehatb1043402010-02-05 08:26:50 -08002058 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002059 try {
Jeff Sharkey56cd6462013-06-07 15:09:15 -07002060 mConnector.execute("asec", "create", id, sizeMb, fstype, new SensitiveArg(key),
2061 ownerUid, external ? "1" : "0");
San Mehat4270e1e2010-01-29 05:32:19 -08002062 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002063 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002064 }
San Mehata181b212010-02-11 06:50:20 -08002065
2066 if (rc == StorageResultCode.OperationSucceeded) {
2067 synchronized (mAsecMountSet) {
2068 mAsecMountSet.add(id);
2069 }
2070 }
San Mehat4270e1e2010-01-29 05:32:19 -08002071 return rc;
San Mehat36972292010-01-06 11:06:32 -08002072 }
2073
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002074 @Override
2075 public int resizeSecureContainer(String id, int sizeMb, String key) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002076 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002077 waitForReady();
2078 warnOnNotMounted();
2079
2080 int rc = StorageResultCode.OperationSucceeded;
2081 try {
2082 mConnector.execute("asec", "resize", id, sizeMb, new SensitiveArg(key));
2083 } catch (NativeDaemonConnectorException e) {
2084 rc = StorageResultCode.OperationFailedInternalError;
2085 }
2086 return rc;
2087 }
2088
San Mehat4270e1e2010-01-29 05:32:19 -08002089 public int finalizeSecureContainer(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002090 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehatb1043402010-02-05 08:26:50 -08002091 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002092
San Mehatb1043402010-02-05 08:26:50 -08002093 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002094 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002095 mConnector.execute("asec", "finalize", id);
San Mehata181b212010-02-11 06:50:20 -08002096 /*
2097 * Finalization does a remount, so no need
2098 * to update mAsecMountSet
2099 */
San Mehat4270e1e2010-01-29 05:32:19 -08002100 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002101 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002102 }
San Mehat4270e1e2010-01-29 05:32:19 -08002103 return rc;
San Mehat36972292010-01-06 11:06:32 -08002104 }
2105
Kenny Root6dceb882012-04-12 14:23:49 -07002106 public int fixPermissionsSecureContainer(String id, int gid, String filename) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002107 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Kenny Root6dceb882012-04-12 14:23:49 -07002108 warnOnNotMounted();
2109
2110 int rc = StorageResultCode.OperationSucceeded;
2111 try {
2112 mConnector.execute("asec", "fixperms", id, gid, filename);
2113 /*
2114 * Fix permissions does a remount, so no need to update
2115 * mAsecMountSet
2116 */
2117 } catch (NativeDaemonConnectorException e) {
2118 rc = StorageResultCode.OperationFailedInternalError;
2119 }
2120 return rc;
2121 }
2122
San Mehatd9709982010-02-18 11:43:03 -08002123 public int destroySecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002124 enforcePermission(android.Manifest.permission.ASEC_DESTROY);
San Mehat207e5382010-02-04 20:46:54 -08002125 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002126 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002127
Kenny Rootaa485402010-09-14 14:49:41 -07002128 /*
2129 * Force a GC to make sure AssetManagers in other threads of the
2130 * system_server are cleaned up. We have to do this since AssetManager
2131 * instances are kept as a WeakReference and it's possible we have files
2132 * open on the external storage.
2133 */
2134 Runtime.getRuntime().gc();
2135
San Mehatb1043402010-02-05 08:26:50 -08002136 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002137 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002138 final Command cmd = new Command("asec", "destroy", id);
2139 if (force) {
2140 cmd.appendArg("force");
2141 }
2142 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002143 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002144 int code = e.getCode();
2145 if (code == VoldResponseCode.OpFailedStorageBusy) {
2146 rc = StorageResultCode.OperationFailedStorageBusy;
2147 } else {
2148 rc = StorageResultCode.OperationFailedInternalError;
2149 }
San Mehat02735bc2010-01-26 15:18:08 -08002150 }
San Mehata181b212010-02-11 06:50:20 -08002151
2152 if (rc == StorageResultCode.OperationSucceeded) {
2153 synchronized (mAsecMountSet) {
2154 if (mAsecMountSet.contains(id)) {
2155 mAsecMountSet.remove(id);
2156 }
2157 }
2158 }
2159
San Mehat4270e1e2010-01-29 05:32:19 -08002160 return rc;
San Mehat36972292010-01-06 11:06:32 -08002161 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002162
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002163 public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002164 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002165 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002166 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002167
San Mehata181b212010-02-11 06:50:20 -08002168 synchronized (mAsecMountSet) {
2169 if (mAsecMountSet.contains(id)) {
2170 return StorageResultCode.OperationFailedStorageMounted;
2171 }
2172 }
2173
San Mehatb1043402010-02-05 08:26:50 -08002174 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002175 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002176 mConnector.execute("asec", "mount", id, new SensitiveArg(key), ownerUid,
2177 readOnly ? "ro" : "rw");
San Mehat4270e1e2010-01-29 05:32:19 -08002178 } catch (NativeDaemonConnectorException e) {
Kenny Rootf0304622010-03-19 19:20:42 -07002179 int code = e.getCode();
2180 if (code != VoldResponseCode.OpFailedStorageBusy) {
2181 rc = StorageResultCode.OperationFailedInternalError;
2182 }
San Mehat02735bc2010-01-26 15:18:08 -08002183 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002184
2185 if (rc == StorageResultCode.OperationSucceeded) {
2186 synchronized (mAsecMountSet) {
2187 mAsecMountSet.add(id);
2188 }
2189 }
San Mehat4270e1e2010-01-29 05:32:19 -08002190 return rc;
San Mehat36972292010-01-06 11:06:32 -08002191 }
2192
San Mehatd9709982010-02-18 11:43:03 -08002193 public int unmountSecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002194 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002195 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002196 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002197
San Mehat6cdd9c02010-02-09 14:45:20 -08002198 synchronized (mAsecMountSet) {
2199 if (!mAsecMountSet.contains(id)) {
San Mehata181b212010-02-11 06:50:20 -08002200 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehat6cdd9c02010-02-09 14:45:20 -08002201 }
2202 }
2203
Kenny Rootaa485402010-09-14 14:49:41 -07002204 /*
2205 * Force a GC to make sure AssetManagers in other threads of the
2206 * system_server are cleaned up. We have to do this since AssetManager
2207 * instances are kept as a WeakReference and it's possible we have files
2208 * open on the external storage.
2209 */
2210 Runtime.getRuntime().gc();
2211
San Mehatb1043402010-02-05 08:26:50 -08002212 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002213 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002214 final Command cmd = new Command("asec", "unmount", id);
2215 if (force) {
2216 cmd.appendArg("force");
2217 }
2218 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002219 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002220 int code = e.getCode();
2221 if (code == VoldResponseCode.OpFailedStorageBusy) {
2222 rc = StorageResultCode.OperationFailedStorageBusy;
2223 } else {
2224 rc = StorageResultCode.OperationFailedInternalError;
2225 }
San Mehat02735bc2010-01-26 15:18:08 -08002226 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002227
2228 if (rc == StorageResultCode.OperationSucceeded) {
2229 synchronized (mAsecMountSet) {
2230 mAsecMountSet.remove(id);
2231 }
2232 }
San Mehat4270e1e2010-01-29 05:32:19 -08002233 return rc;
San Mehat9dba7092010-01-18 06:47:41 -08002234 }
2235
San Mehat6cdd9c02010-02-09 14:45:20 -08002236 public boolean isSecureContainerMounted(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002237 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat6cdd9c02010-02-09 14:45:20 -08002238 waitForReady();
2239 warnOnNotMounted();
2240
2241 synchronized (mAsecMountSet) {
2242 return mAsecMountSet.contains(id);
2243 }
2244 }
2245
San Mehat4270e1e2010-01-29 05:32:19 -08002246 public int renameSecureContainer(String oldId, String newId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002247 enforcePermission(android.Manifest.permission.ASEC_RENAME);
San Mehat207e5382010-02-04 20:46:54 -08002248 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002249 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002250
San Mehata181b212010-02-11 06:50:20 -08002251 synchronized (mAsecMountSet) {
San Mehat85451ee2010-02-24 08:54:18 -08002252 /*
Jason parks9ed98bc2011-01-17 09:58:35 -06002253 * Because a mounted container has active internal state which cannot be
San Mehat85451ee2010-02-24 08:54:18 -08002254 * changed while active, we must ensure both ids are not currently mounted.
2255 */
2256 if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
San Mehata181b212010-02-11 06:50:20 -08002257 return StorageResultCode.OperationFailedStorageMounted;
2258 }
2259 }
2260
San Mehatb1043402010-02-05 08:26:50 -08002261 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002262 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002263 mConnector.execute("asec", "rename", oldId, newId);
San Mehat4270e1e2010-01-29 05:32:19 -08002264 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002265 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002266 }
San Mehata181b212010-02-11 06:50:20 -08002267
San Mehat4270e1e2010-01-29 05:32:19 -08002268 return rc;
San Mehat45f61042010-01-23 08:12:43 -08002269 }
2270
San Mehat4270e1e2010-01-29 05:32:19 -08002271 public String getSecureContainerPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002272 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002273 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002274 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002275
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002276 final NativeDaemonEvent event;
San Mehat2d66cef2010-03-23 11:12:52 -07002277 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002278 event = mConnector.execute("asec", "path", id);
2279 event.checkCode(VoldResponseCode.AsecPathResult);
2280 return event.getMessage();
San Mehat2d66cef2010-03-23 11:12:52 -07002281 } catch (NativeDaemonConnectorException e) {
2282 int code = e.getCode();
2283 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Fredrik Helmera20c8ef2011-02-09 16:16:10 +01002284 Slog.i(TAG, String.format("Container '%s' not found", id));
2285 return null;
San Mehat22dd86e2010-01-12 12:21:18 -08002286 } else {
San Mehat2d66cef2010-03-23 11:12:52 -07002287 throw new IllegalStateException(String.format("Unexpected response code %d", code));
San Mehat22dd86e2010-01-12 12:21:18 -08002288 }
2289 }
San Mehat22dd86e2010-01-12 12:21:18 -08002290 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002291
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002292 public String getSecureContainerFilesystemPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002293 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002294 waitForReady();
2295 warnOnNotMounted();
2296
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002297 final NativeDaemonEvent event;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002298 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002299 event = mConnector.execute("asec", "fspath", id);
2300 event.checkCode(VoldResponseCode.AsecPathResult);
2301 return event.getMessage();
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002302 } catch (NativeDaemonConnectorException e) {
2303 int code = e.getCode();
2304 if (code == VoldResponseCode.OpFailedStorageNotFound) {
2305 Slog.i(TAG, String.format("Container '%s' not found", id));
2306 return null;
2307 } else {
2308 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2309 }
2310 }
2311 }
2312
Jeff Sharkey48877892015-03-18 11:27:19 -07002313 @Override
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002314 public void finishMediaUpdate() {
Jeff Sharkey9527b222015-06-24 15:24:48 -07002315 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
Rubin Xucd7a0142015-04-17 23:45:27 +01002316 throw new SecurityException("no permission to call finishMediaUpdate()");
2317 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002318 if (mUnmountSignal != null) {
2319 mUnmountSignal.countDown();
2320 } else {
2321 Slog.w(TAG, "Odd, nobody asked to unmount?");
2322 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002323 }
Kenny Root02c87302010-07-01 08:10:18 -07002324
Kenny Roota02b8b02010-08-05 16:14:17 -07002325 private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
2326 if (callerUid == android.os.Process.SYSTEM_UID) {
2327 return true;
2328 }
2329
Kenny Root02c87302010-07-01 08:10:18 -07002330 if (packageName == null) {
2331 return false;
2332 }
2333
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07002334 final int packageUid = mPms.getPackageUid(packageName, UserHandle.getUserId(callerUid));
Kenny Root02c87302010-07-01 08:10:18 -07002335
2336 if (DEBUG_OBB) {
2337 Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
2338 packageUid + ", callerUid = " + callerUid);
2339 }
2340
2341 return callerUid == packageUid;
2342 }
2343
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002344 public String getMountedObbPath(String rawPath) {
2345 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002346
Kenny Root02c87302010-07-01 08:10:18 -07002347 waitForReady();
2348 warnOnNotMounted();
2349
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002350 final ObbState state;
Rubin Xucd7a0142015-04-17 23:45:27 +01002351 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002352 state = mObbPathToStateMap.get(rawPath);
2353 }
2354 if (state == null) {
2355 Slog.w(TAG, "Failed to find OBB mounted at " + rawPath);
2356 return null;
2357 }
2358
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002359 final NativeDaemonEvent event;
Kenny Root02c87302010-07-01 08:10:18 -07002360 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07002361 event = mConnector.execute("obb", "path", state.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002362 event.checkCode(VoldResponseCode.AsecPathResult);
2363 return event.getMessage();
Kenny Root02c87302010-07-01 08:10:18 -07002364 } catch (NativeDaemonConnectorException e) {
2365 int code = e.getCode();
2366 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Kenny Roota02b8b02010-08-05 16:14:17 -07002367 return null;
Kenny Root02c87302010-07-01 08:10:18 -07002368 } else {
2369 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2370 }
2371 }
2372 }
2373
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002374 @Override
2375 public boolean isObbMounted(String rawPath) {
2376 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002377 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002378 return mObbPathToStateMap.containsKey(rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002379 }
Kenny Root02c87302010-07-01 08:10:18 -07002380 }
2381
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002382 @Override
2383 public void mountObb(
2384 String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) {
2385 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2386 Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
2387 Preconditions.checkNotNull(token, "token cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002388
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002389 final int callingUid = Binder.getCallingUid();
2390 final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce);
2391 final ObbAction action = new MountObbAction(obbState, key, callingUid);
Kenny Roota02b8b02010-08-05 16:14:17 -07002392 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
2393
2394 if (DEBUG_OBB)
2395 Slog.i(TAG, "Send to OBB handler: " + action.toString());
Kenny Root02c87302010-07-01 08:10:18 -07002396 }
2397
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002398 @Override
2399 public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
2400 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2401
2402 final ObbState existingState;
Rubin Xucd7a0142015-04-17 23:45:27 +01002403 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002404 existingState = mObbPathToStateMap.get(rawPath);
Kenny Rootf1121dc2010-09-29 07:30:53 -07002405 }
2406
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002407 if (existingState != null) {
2408 // TODO: separate state object from request data
2409 final int callingUid = Binder.getCallingUid();
2410 final ObbState newState = new ObbState(
2411 rawPath, existingState.canonicalPath, callingUid, token, nonce);
2412 final ObbAction action = new UnmountObbAction(newState, force);
2413 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root02c87302010-07-01 08:10:18 -07002414
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002415 if (DEBUG_OBB)
2416 Slog.i(TAG, "Send to OBB handler: " + action.toString());
2417 } else {
2418 Slog.w(TAG, "Unknown OBB mount at " + rawPath);
2419 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002420 }
2421
Ben Komalo444eca22011-09-01 15:17:44 -07002422 @Override
2423 public int getEncryptionState() {
2424 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2425 "no permission to access the crypt keeper");
2426
2427 waitForReady();
2428
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002429 final NativeDaemonEvent event;
Ben Komalo444eca22011-09-01 15:17:44 -07002430 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002431 event = mCryptConnector.execute("cryptfs", "cryptocomplete");
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002432 return Integer.parseInt(event.getMessage());
Ben Komalo444eca22011-09-01 15:17:44 -07002433 } catch (NumberFormatException e) {
2434 // Bad result - unexpected.
2435 Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
2436 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2437 } catch (NativeDaemonConnectorException e) {
2438 // Something bad happened.
2439 Slog.w(TAG, "Error in communicating with cryptfs in validating");
2440 return ENCRYPTION_STATE_ERROR_UNKNOWN;
2441 }
2442 }
2443
2444 @Override
Jason parks5af0b912010-11-29 09:05:25 -06002445 public int decryptStorage(String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002446 if (TextUtils.isEmpty(password)) {
2447 throw new IllegalArgumentException("password cannot be empty");
Jason parks5af0b912010-11-29 09:05:25 -06002448 }
2449
Jason parks8888c592011-01-20 22:46:41 -06002450 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2451 "no permission to access the crypt keeper");
Jason parks5af0b912010-11-29 09:05:25 -06002452
2453 waitForReady();
2454
2455 if (DEBUG_EVENTS) {
2456 Slog.i(TAG, "decrypting storage...");
2457 }
2458
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002459 final NativeDaemonEvent event;
Jason parks5af0b912010-11-29 09:05:25 -06002460 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002461 event = mCryptConnector.execute("cryptfs", "checkpw", new SensitiveArg(password));
Jason parks9ed98bc2011-01-17 09:58:35 -06002462
Fredrik Roubertda6aedf2011-12-20 17:34:43 +01002463 final int code = Integer.parseInt(event.getMessage());
Jason parks9ed98bc2011-01-17 09:58:35 -06002464 if (code == 0) {
2465 // Decrypt was successful. Post a delayed message before restarting in order
2466 // to let the UI to clear itself
2467 mHandler.postDelayed(new Runnable() {
2468 public void run() {
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002469 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002470 mCryptConnector.execute("cryptfs", "restart");
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002471 } catch (NativeDaemonConnectorException e) {
2472 Slog.e(TAG, "problem executing in background", e);
2473 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002474 }
Jason parksf7b3cd42011-01-27 09:28:25 -06002475 }, 1000); // 1 second
Jason parks9ed98bc2011-01-17 09:58:35 -06002476 }
2477
2478 return code;
Jason parks5af0b912010-11-29 09:05:25 -06002479 } catch (NativeDaemonConnectorException e) {
2480 // Decryption failed
2481 return e.getCode();
2482 }
Jason parks5af0b912010-11-29 09:05:25 -06002483 }
2484
Paul Lawrence46791e72014-04-03 09:10:26 -07002485 public int encryptStorage(int type, String password) {
2486 if (TextUtils.isEmpty(password) && type != StorageManager.CRYPT_TYPE_DEFAULT) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002487 throw new IllegalArgumentException("password cannot be empty");
Jason parks56aa5322011-01-07 09:01:15 -06002488 }
2489
Jason parks8888c592011-01-20 22:46:41 -06002490 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2491 "no permission to access the crypt keeper");
Jason parks56aa5322011-01-07 09:01:15 -06002492
2493 waitForReady();
2494
2495 if (DEBUG_EVENTS) {
Jason parks8888c592011-01-20 22:46:41 -06002496 Slog.i(TAG, "encrypting storage...");
Jason parks56aa5322011-01-07 09:01:15 -06002497 }
2498
2499 try {
Paul Lawrence5096d9e2015-09-09 13:05:45 -07002500 if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
2501 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2502 CRYPTO_TYPES[type]);
2503 } else {
2504 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2505 CRYPTO_TYPES[type], new SensitiveArg(password));
2506 }
Jason parks56aa5322011-01-07 09:01:15 -06002507 } catch (NativeDaemonConnectorException e) {
2508 // Encryption failed
2509 return e.getCode();
2510 }
2511
2512 return 0;
2513 }
2514
Paul Lawrence8e397362014-01-27 15:22:30 -08002515 /** Set the password for encrypting the master key.
2516 * @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
2517 * @param password The password to set.
2518 */
2519 public int changeEncryptionPassword(int type, String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002520 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2521 "no permission to access the crypt keeper");
2522
2523 waitForReady();
2524
2525 if (DEBUG_EVENTS) {
2526 Slog.i(TAG, "changing encryption password...");
2527 }
2528
2529 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002530 NativeDaemonEvent event = mCryptConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type],
Paul Lawrence05487612015-06-09 13:35:38 -07002531 new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002532 return Integer.parseInt(event.getMessage());
Jason parksf7b3cd42011-01-27 09:28:25 -06002533 } catch (NativeDaemonConnectorException e) {
2534 // Encryption failed
2535 return e.getCode();
2536 }
2537 }
2538
Christopher Tate32418be2011-10-10 13:51:12 -07002539 /**
2540 * Validate a user-supplied password string with cryptfs
2541 */
2542 @Override
2543 public int verifyEncryptionPassword(String password) throws RemoteException {
2544 // Only the system process is permitted to validate passwords
2545 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2546 throw new SecurityException("no permission to access the crypt keeper");
2547 }
2548
2549 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2550 "no permission to access the crypt keeper");
2551
2552 if (TextUtils.isEmpty(password)) {
2553 throw new IllegalArgumentException("password cannot be empty");
2554 }
2555
2556 waitForReady();
2557
2558 if (DEBUG_EVENTS) {
2559 Slog.i(TAG, "validating encryption password...");
2560 }
2561
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002562 final NativeDaemonEvent event;
Christopher Tate32418be2011-10-10 13:51:12 -07002563 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002564 event = mCryptConnector.execute("cryptfs", "verifypw", new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002565 Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
2566 return Integer.parseInt(event.getMessage());
Christopher Tate32418be2011-10-10 13:51:12 -07002567 } catch (NativeDaemonConnectorException e) {
2568 // Encryption failed
2569 return e.getCode();
2570 }
2571 }
2572
Paul Lawrence8e397362014-01-27 15:22:30 -08002573 /**
2574 * Get the type of encryption used to encrypt the master key.
2575 * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
2576 */
2577 @Override
Svetoslav16e4a1a2014-09-29 18:16:20 -07002578 public int getPasswordType() {
Paul Lawrence8e397362014-01-27 15:22:30 -08002579
2580 waitForReady();
2581
2582 final NativeDaemonEvent event;
2583 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002584 event = mCryptConnector.execute("cryptfs", "getpwtype");
Paul Lawrence8e397362014-01-27 15:22:30 -08002585 for (int i = 0; i < CRYPTO_TYPES.length; ++i) {
2586 if (CRYPTO_TYPES[i].equals(event.getMessage()))
2587 return i;
2588 }
2589
2590 throw new IllegalStateException("unexpected return from cryptfs");
2591 } catch (NativeDaemonConnectorException e) {
2592 throw e.rethrowAsParcelableException();
2593 }
2594 }
2595
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002596 /**
2597 * Set a field in the crypto header.
2598 * @param field field to set
2599 * @param contents contents to set in field
2600 */
2601 @Override
2602 public void setField(String field, String contents) throws RemoteException {
2603
2604 waitForReady();
2605
2606 final NativeDaemonEvent event;
2607 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002608 event = mCryptConnector.execute("cryptfs", "setfield", field, contents);
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002609 } catch (NativeDaemonConnectorException e) {
2610 throw e.rethrowAsParcelableException();
2611 }
2612 }
2613
2614 /**
2615 * Gets a field from the crypto header.
2616 * @param field field to get
2617 * @return contents of field
2618 */
2619 @Override
2620 public String getField(String field) throws RemoteException {
2621
2622 waitForReady();
2623
2624 final NativeDaemonEvent event;
2625 try {
2626 final String[] contents = NativeDaemonEvent.filterMessageList(
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002627 mCryptConnector.executeForList("cryptfs", "getfield", field),
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002628 VoldResponseCode.CryptfsGetfieldResult);
2629 String result = new String();
2630 for (String content : contents) {
2631 result += content;
2632 }
2633 return result;
2634 } catch (NativeDaemonConnectorException e) {
2635 throw e.rethrowAsParcelableException();
2636 }
2637 }
2638
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002639 /**
2640 * Is userdata convertible to file based encryption?
2641 * @return non zero for convertible
2642 */
2643 @Override
2644 public boolean isConvertibleToFBE() throws RemoteException {
2645
2646 waitForReady();
2647
2648 final NativeDaemonEvent event;
2649 try {
2650 event = mCryptConnector.execute("cryptfs", "isConvertibleToFBE");
2651 return Integer.parseInt(event.getMessage()) != 0;
2652 } catch (NativeDaemonConnectorException e) {
2653 throw e.rethrowAsParcelableException();
2654 }
2655 }
2656
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002657 @Override
Paul Lawrence945490c2014-03-27 16:37:28 +00002658 public String getPassword() throws RemoteException {
Rubin Xucd7a0142015-04-17 23:45:27 +01002659 mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE,
2660 "only keyguard can retrieve password");
Paul Lawrence945490c2014-03-27 16:37:28 +00002661 if (!isReady()) {
2662 return new String();
2663 }
2664
2665 final NativeDaemonEvent event;
2666 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002667 event = mCryptConnector.execute("cryptfs", "getpw");
Paul Lawrence24063b52015-01-06 13:11:23 -08002668 if ("-1".equals(event.getMessage())) {
2669 // -1 equals no password
2670 return null;
2671 }
Paul Lawrence05487612015-06-09 13:35:38 -07002672 return event.getMessage();
Paul Lawrence945490c2014-03-27 16:37:28 +00002673 } catch (NativeDaemonConnectorException e) {
2674 throw e.rethrowAsParcelableException();
Paul Lawrence24063b52015-01-06 13:11:23 -08002675 } catch (IllegalArgumentException e) {
2676 Slog.e(TAG, "Invalid response to getPassword");
2677 return null;
Paul Lawrence945490c2014-03-27 16:37:28 +00002678 }
2679 }
2680
2681 @Override
2682 public void clearPassword() throws RemoteException {
2683 if (!isReady()) {
2684 return;
2685 }
2686
2687 final NativeDaemonEvent event;
2688 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002689 event = mCryptConnector.execute("cryptfs", "clearpw");
Paul Lawrence945490c2014-03-27 16:37:28 +00002690 } catch (NativeDaemonConnectorException e) {
2691 throw e.rethrowAsParcelableException();
2692 }
2693 }
2694
2695 @Override
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002696 public void createUserKey(int userId, int serialNumber) {
2697 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002698 waitForReady();
2699
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002700 try {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002701 mCryptConnector.execute("cryptfs", "create_user_key", userId, serialNumber);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002702 } catch (NativeDaemonConnectorException e) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002703 throw e.rethrowAsParcelableException();
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002704 }
2705 }
2706
Paul Crowley7ec733f2015-05-19 12:42:00 +01002707 @Override
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002708 public void destroyUserKey(int userId) {
2709 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowley7ec733f2015-05-19 12:42:00 +01002710 waitForReady();
2711
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002712 try {
2713 mCryptConnector.execute("cryptfs", "destroy_user_key", userId);
2714 } catch (NativeDaemonConnectorException e) {
2715 throw e.rethrowAsParcelableException();
2716 }
2717 }
2718
2719 @Override
2720 public void unlockUserKey(int userId, int serialNumber, byte[] token) {
2721 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2722 waitForReady();
2723
2724 final String encodedToken;
2725 if (ArrayUtils.isEmpty(token)) {
2726 encodedToken = "!";
2727 } else {
2728 encodedToken = HexDump.toHexString(token);
Paul Crowley7ec733f2015-05-19 12:42:00 +01002729 }
2730
2731 try {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002732 mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber,
2733 new SensitiveArg(encodedToken));
Paul Crowley7ec733f2015-05-19 12:42:00 +01002734 } catch (NativeDaemonConnectorException e) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002735 throw e.rethrowAsParcelableException();
2736 }
2737
2738 synchronized (mLock) {
2739 mUnlockedUsers = ArrayUtils.appendInt(mUnlockedUsers, userId);
2740 }
2741 }
2742
2743 @Override
2744 public void lockUserKey(int userId) {
2745 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2746 waitForReady();
2747
2748 try {
2749 mCryptConnector.execute("cryptfs", "lock_user_key", userId);
2750 } catch (NativeDaemonConnectorException e) {
2751 throw e.rethrowAsParcelableException();
2752 }
2753
2754 synchronized (mLock) {
2755 mUnlockedUsers = ArrayUtils.removeInt(mUnlockedUsers, userId);
2756 }
2757 }
2758
2759 @Override
2760 public boolean isUserKeyUnlocked(int userId) {
Jeff Sharkeyba512352015-11-12 20:17:45 -08002761 if (StorageManager.isFileBasedEncryptionEnabled()) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002762 synchronized (mLock) {
2763 return ArrayUtils.contains(mUnlockedUsers, userId);
2764 }
2765 } else {
2766 return true;
2767 }
2768 }
2769
2770 @Override
2771 public void prepareUserStorage(String volumeUuid, int userId, int serialNumber) {
2772 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2773 waitForReady();
2774
2775 try {
2776 mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid),
2777 userId, serialNumber);
2778 } catch (NativeDaemonConnectorException e) {
2779 throw e.rethrowAsParcelableException();
Paul Crowley7ec733f2015-05-19 12:42:00 +01002780 }
2781 }
2782
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002783 @Override
Daichi Hirono9e8d9e22015-11-13 14:37:00 +09002784 public ParcelFileDescriptor mountAppFuse(String name) throws RemoteException {
2785 // TODO: Invoke vold to mount app fuse.
2786 throw new UnsupportedOperationException();
2787 }
2788
2789 @Override
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002790 public int mkdirs(String callingPkg, String appPath) {
2791 final int userId = UserHandle.getUserId(Binder.getCallingUid());
2792 final UserEnvironment userEnv = new UserEnvironment(userId);
2793
2794 // Validate that reported package name belongs to caller
2795 final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
2796 Context.APP_OPS_SERVICE);
2797 appOps.checkPackage(Binder.getCallingUid(), callingPkg);
2798
Jeff Sharkey48877892015-03-18 11:27:19 -07002799 File appFile = null;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002800 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07002801 appFile = new File(appPath).getCanonicalFile();
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002802 } catch (IOException e) {
2803 Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
2804 return -1;
2805 }
2806
2807 // Try translating the app path into a vold path, but require that it
2808 // belong to the calling package.
Jeff Sharkey48877892015-03-18 11:27:19 -07002809 if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) ||
2810 FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) ||
2811 FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) {
2812 appPath = appFile.getAbsolutePath();
2813 if (!appPath.endsWith("/")) {
2814 appPath = appPath + "/";
2815 }
2816
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002817 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07002818 mConnector.execute("volume", "mkdirs", appPath);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002819 return 0;
2820 } catch (NativeDaemonConnectorException e) {
2821 return e.getCode();
2822 }
2823 }
2824
Jeff Sharkey48877892015-03-18 11:27:19 -07002825 throw new SecurityException("Invalid mkdirs path: " + appFile);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07002826 }
2827
2828 @Override
Jeff Sharkey46349872015-07-28 10:49:47 -07002829 public StorageVolume[] getVolumeList(int uid, String packageName, int flags) {
2830 final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0;
2831
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002832 final ArrayList<StorageVolume> res = new ArrayList<>();
Jeff Sharkey48877892015-03-18 11:27:19 -07002833 boolean foundPrimary = false;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002834
Svet Ganov6ee871e2015-07-10 14:29:33 -07002835 final int userId = UserHandle.getUserId(uid);
Svetoslav38c3dbb2015-07-14 11:27:06 -07002836 final boolean reportUnmounted;
Svetoslav38c3dbb2015-07-14 11:27:06 -07002837 final long identity = Binder.clearCallingIdentity();
2838 try {
2839 reportUnmounted = !mMountServiceInternal.hasExternalStorage(
2840 uid, packageName);
2841 } finally {
2842 Binder.restoreCallingIdentity(identity);
2843 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07002844
Jeff Sharkey48877892015-03-18 11:27:19 -07002845 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002846 for (int i = 0; i < mVolumes.size(); i++) {
2847 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey46349872015-07-28 10:49:47 -07002848 if (forWrite ? vol.isVisibleForWrite(userId) : vol.isVisibleForRead(userId)) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07002849 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
2850 reportUnmounted);
Jeff Sharkey48877892015-03-18 11:27:19 -07002851 if (vol.isPrimary()) {
2852 res.add(0, userVol);
2853 foundPrimary = true;
2854 } else {
2855 res.add(userVol);
2856 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002857 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002858 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002859 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002860
2861 if (!foundPrimary) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002862 Log.w(TAG, "No primary storage defined yet; hacking together a stub");
Jeff Sharkey48877892015-03-18 11:27:19 -07002863
2864 final boolean primaryPhysical = SystemProperties.getBoolean(
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002865 StorageManager.PROP_PRIMARY_PHYSICAL, false);
Jeff Sharkey48877892015-03-18 11:27:19 -07002866
2867 final String id = "stub_primary";
2868 final File path = Environment.getLegacyExternalStorageDirectory();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002869 final String description = mContext.getString(android.R.string.unknownName);
Jeff Sharkey48877892015-03-18 11:27:19 -07002870 final boolean primary = true;
2871 final boolean removable = primaryPhysical;
2872 final boolean emulated = !primaryPhysical;
2873 final long mtpReserveSize = 0L;
2874 final boolean allowMassStorage = false;
2875 final long maxFileSize = 0L;
2876 final UserHandle owner = new UserHandle(userId);
2877 final String uuid = null;
Jeff Sharkey48877892015-03-18 11:27:19 -07002878 final String state = Environment.MEDIA_REMOVED;
2879
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07002880 res.add(0, new StorageVolume(id, StorageVolume.STORAGE_ID_INVALID, path,
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002881 description, primary, removable, emulated, mtpReserveSize,
2882 allowMassStorage, maxFileSize, owner, uuid, state));
Jeff Sharkey48877892015-03-18 11:27:19 -07002883 }
2884
2885 return res.toArray(new StorageVolume[res.size()]);
Mike Lockwood8fa5f802011-03-24 08:12:30 -07002886 }
2887
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002888 @Override
2889 public DiskInfo[] getDisks() {
2890 synchronized (mLock) {
2891 final DiskInfo[] res = new DiskInfo[mDisks.size()];
2892 for (int i = 0; i < mDisks.size(); i++) {
2893 res[i] = mDisks.valueAt(i);
2894 }
2895 return res;
2896 }
2897 }
2898
2899 @Override
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07002900 public VolumeInfo[] getVolumes(int flags) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002901 synchronized (mLock) {
2902 final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
2903 for (int i = 0; i < mVolumes.size(); i++) {
2904 res[i] = mVolumes.valueAt(i);
2905 }
2906 return res;
2907 }
2908 }
2909
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07002910 @Override
2911 public VolumeRecord[] getVolumeRecords(int flags) {
2912 synchronized (mLock) {
2913 final VolumeRecord[] res = new VolumeRecord[mRecords.size()];
2914 for (int i = 0; i < mRecords.size(); i++) {
2915 res[i] = mRecords.valueAt(i);
2916 }
2917 return res;
2918 }
2919 }
2920
Kenny Rootaf9d6672010-10-08 09:21:39 -07002921 private void addObbStateLocked(ObbState obbState) throws RemoteException {
2922 final IBinder binder = obbState.getBinder();
2923 List<ObbState> obbStates = mObbMounts.get(binder);
Kenny Root5919ac62010-10-05 09:49:40 -07002924
Kenny Rootaf9d6672010-10-08 09:21:39 -07002925 if (obbStates == null) {
2926 obbStates = new ArrayList<ObbState>();
2927 mObbMounts.put(binder, obbStates);
2928 } else {
2929 for (final ObbState o : obbStates) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002930 if (o.rawPath.equals(obbState.rawPath)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07002931 throw new IllegalStateException("Attempt to add ObbState twice. "
2932 + "This indicates an error in the MountService logic.");
Kenny Root5919ac62010-10-05 09:49:40 -07002933 }
2934 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002935 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07002936
2937 obbStates.add(obbState);
2938 try {
2939 obbState.link();
2940 } catch (RemoteException e) {
2941 /*
2942 * The binder died before we could link it, so clean up our state
2943 * and return failure.
2944 */
2945 obbStates.remove(obbState);
2946 if (obbStates.isEmpty()) {
2947 mObbMounts.remove(binder);
2948 }
2949
2950 // Rethrow the error so mountObb can get it
2951 throw e;
2952 }
2953
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002954 mObbPathToStateMap.put(obbState.rawPath, obbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07002955 }
2956
Kenny Rootaf9d6672010-10-08 09:21:39 -07002957 private void removeObbStateLocked(ObbState obbState) {
2958 final IBinder binder = obbState.getBinder();
2959 final List<ObbState> obbStates = mObbMounts.get(binder);
2960 if (obbStates != null) {
2961 if (obbStates.remove(obbState)) {
2962 obbState.unlink();
Kenny Root05105f72010-09-22 17:29:43 -07002963 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07002964 if (obbStates.isEmpty()) {
2965 mObbMounts.remove(binder);
2966 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002967 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002968
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002969 mObbPathToStateMap.remove(obbState.rawPath);
Kenny Root38cf8862010-09-26 14:18:51 -07002970 }
2971
Kenny Roota02b8b02010-08-05 16:14:17 -07002972 private class ObbActionHandler extends Handler {
2973 private boolean mBound = false;
Kenny Root480afe72010-10-07 10:17:50 -07002974 private final List<ObbAction> mActions = new LinkedList<ObbAction>();
Kenny Roota02b8b02010-08-05 16:14:17 -07002975
2976 ObbActionHandler(Looper l) {
2977 super(l);
2978 }
2979
2980 @Override
2981 public void handleMessage(Message msg) {
2982 switch (msg.what) {
2983 case OBB_RUN_ACTION: {
Kenny Root480afe72010-10-07 10:17:50 -07002984 final ObbAction action = (ObbAction) msg.obj;
Kenny Roota02b8b02010-08-05 16:14:17 -07002985
2986 if (DEBUG_OBB)
2987 Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
2988
2989 // If a bind was already initiated we don't really
2990 // need to do anything. The pending install
2991 // will be processed later on.
2992 if (!mBound) {
2993 // If this is the only one pending we might
2994 // have to bind to the service again.
2995 if (!connectToService()) {
2996 Slog.e(TAG, "Failed to bind to media container service");
2997 action.handleError();
2998 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07002999 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003000 }
Kenny Root735de3b2010-09-30 14:11:39 -07003001
Kenny Root735de3b2010-09-30 14:11:39 -07003002 mActions.add(action);
Kenny Roota02b8b02010-08-05 16:14:17 -07003003 break;
3004 }
3005 case OBB_MCS_BOUND: {
3006 if (DEBUG_OBB)
3007 Slog.i(TAG, "OBB_MCS_BOUND");
3008 if (msg.obj != null) {
3009 mContainerService = (IMediaContainerService) msg.obj;
3010 }
3011 if (mContainerService == null) {
3012 // Something seriously wrong. Bail out
3013 Slog.e(TAG, "Cannot bind to media container service");
3014 for (ObbAction action : mActions) {
3015 // Indicate service bind error
3016 action.handleError();
3017 }
3018 mActions.clear();
3019 } else if (mActions.size() > 0) {
Kenny Root480afe72010-10-07 10:17:50 -07003020 final ObbAction action = mActions.get(0);
Kenny Roota02b8b02010-08-05 16:14:17 -07003021 if (action != null) {
3022 action.execute(this);
3023 }
3024 } else {
3025 // Should never happen ideally.
3026 Slog.w(TAG, "Empty queue");
3027 }
3028 break;
3029 }
3030 case OBB_MCS_RECONNECT: {
3031 if (DEBUG_OBB)
3032 Slog.i(TAG, "OBB_MCS_RECONNECT");
3033 if (mActions.size() > 0) {
3034 if (mBound) {
3035 disconnectService();
3036 }
3037 if (!connectToService()) {
3038 Slog.e(TAG, "Failed to bind to media container service");
3039 for (ObbAction action : mActions) {
3040 // Indicate service bind error
3041 action.handleError();
3042 }
3043 mActions.clear();
3044 }
3045 }
3046 break;
3047 }
3048 case OBB_MCS_UNBIND: {
3049 if (DEBUG_OBB)
3050 Slog.i(TAG, "OBB_MCS_UNBIND");
3051
3052 // Delete pending install
3053 if (mActions.size() > 0) {
3054 mActions.remove(0);
3055 }
3056 if (mActions.size() == 0) {
3057 if (mBound) {
3058 disconnectService();
3059 }
3060 } else {
3061 // There are more pending requests in queue.
3062 // Just post MCS_BOUND message to trigger processing
3063 // of next pending install.
3064 mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
3065 }
3066 break;
3067 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003068 case OBB_FLUSH_MOUNT_STATE: {
3069 final String path = (String) msg.obj;
3070
3071 if (DEBUG_OBB)
3072 Slog.i(TAG, "Flushing all OBB state for path " + path);
3073
3074 synchronized (mObbMounts) {
3075 final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
3076
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003077 final Iterator<ObbState> i = mObbPathToStateMap.values().iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003078 while (i.hasNext()) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003079 final ObbState state = i.next();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003080
3081 /*
3082 * If this entry's source file is in the volume path
3083 * that got unmounted, remove it because it's no
3084 * longer valid.
3085 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003086 if (state.canonicalPath.startsWith(path)) {
3087 obbStatesToRemove.add(state);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003088 }
3089 }
3090
3091 for (final ObbState obbState : obbStatesToRemove) {
3092 if (DEBUG_OBB)
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003093 Slog.i(TAG, "Removing state for " + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003094
3095 removeObbStateLocked(obbState);
3096
3097 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003098 obbState.token.onObbResult(obbState.rawPath, obbState.nonce,
Kenny Rootaf9d6672010-10-08 09:21:39 -07003099 OnObbStateChangeListener.UNMOUNTED);
3100 } catch (RemoteException e) {
3101 Slog.i(TAG, "Couldn't send unmount notification for OBB: "
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003102 + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003103 }
3104 }
3105 }
3106 break;
3107 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003108 }
3109 }
3110
3111 private boolean connectToService() {
3112 if (DEBUG_OBB)
3113 Slog.i(TAG, "Trying to bind to DefaultContainerService");
3114
3115 Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Jeff Sharkey6dce4962015-07-03 18:08:41 -07003116 if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE,
Xiaohui Chene4de5a02015-09-22 15:33:31 -07003117 UserHandle.SYSTEM)) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003118 mBound = true;
3119 return true;
3120 }
3121 return false;
3122 }
3123
3124 private void disconnectService() {
3125 mContainerService = null;
3126 mBound = false;
3127 mContext.unbindService(mDefContainerConn);
3128 }
3129 }
3130
3131 abstract class ObbAction {
3132 private static final int MAX_RETRIES = 3;
3133 private int mRetries;
3134
3135 ObbState mObbState;
3136
3137 ObbAction(ObbState obbState) {
3138 mObbState = obbState;
3139 }
3140
3141 public void execute(ObbActionHandler handler) {
3142 try {
3143 if (DEBUG_OBB)
Ben Komalo444eca22011-09-01 15:17:44 -07003144 Slog.i(TAG, "Starting to execute action: " + toString());
Kenny Roota02b8b02010-08-05 16:14:17 -07003145 mRetries++;
3146 if (mRetries > MAX_RETRIES) {
3147 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
Kenny Root480afe72010-10-07 10:17:50 -07003148 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003149 handleError();
Kenny Roota02b8b02010-08-05 16:14:17 -07003150 } else {
3151 handleExecute();
3152 if (DEBUG_OBB)
3153 Slog.i(TAG, "Posting install MCS_UNBIND");
3154 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
3155 }
3156 } catch (RemoteException e) {
3157 if (DEBUG_OBB)
3158 Slog.i(TAG, "Posting install MCS_RECONNECT");
3159 mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
3160 } catch (Exception e) {
3161 if (DEBUG_OBB)
3162 Slog.d(TAG, "Error handling OBB action", e);
3163 handleError();
Kenny Root17eb6fb2010-10-06 15:02:52 -07003164 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003165 }
3166 }
3167
Kenny Root05105f72010-09-22 17:29:43 -07003168 abstract void handleExecute() throws RemoteException, IOException;
Kenny Roota02b8b02010-08-05 16:14:17 -07003169 abstract void handleError();
Kenny Root38cf8862010-09-26 14:18:51 -07003170
3171 protected ObbInfo getObbInfo() throws IOException {
3172 ObbInfo obbInfo;
3173 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003174 obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003175 } catch (RemoteException e) {
3176 Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003177 + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003178 obbInfo = null;
3179 }
3180 if (obbInfo == null) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003181 throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003182 }
3183 return obbInfo;
3184 }
3185
Kenny Rootaf9d6672010-10-08 09:21:39 -07003186 protected void sendNewStatusOrIgnore(int status) {
3187 if (mObbState == null || mObbState.token == null) {
3188 return;
3189 }
3190
Kenny Root38cf8862010-09-26 14:18:51 -07003191 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003192 mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
Kenny Root38cf8862010-09-26 14:18:51 -07003193 } catch (RemoteException e) {
3194 Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged");
3195 }
3196 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003197 }
3198
3199 class MountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003200 private final String mKey;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003201 private final int mCallingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003202
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003203 MountObbAction(ObbState obbState, String key, int callingUid) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003204 super(obbState);
3205 mKey = key;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003206 mCallingUid = callingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003207 }
3208
Jason parks5af0b912010-11-29 09:05:25 -06003209 @Override
Kenny Root735de3b2010-09-30 14:11:39 -07003210 public void handleExecute() throws IOException, RemoteException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003211 waitForReady();
3212 warnOnNotMounted();
3213
Kenny Root38cf8862010-09-26 14:18:51 -07003214 final ObbInfo obbInfo = getObbInfo();
3215
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003216 if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003217 Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
3218 + " which is owned by " + obbInfo.packageName);
3219 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3220 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003221 }
3222
Kenny Rootaf9d6672010-10-08 09:21:39 -07003223 final boolean isMounted;
3224 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003225 isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003226 }
3227 if (isMounted) {
3228 Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
3229 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
3230 return;
3231 }
3232
Kenny Rootaf9d6672010-10-08 09:21:39 -07003233 final String hashedKey;
3234 if (mKey == null) {
3235 hashedKey = "none";
3236 } else {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003237 try {
Kenny Root3b1abba2010-10-13 15:00:07 -07003238 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
3239
3240 KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
3241 PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
3242 SecretKey key = factory.generateSecret(ks);
3243 BigInteger bi = new BigInteger(key.getEncoded());
3244 hashedKey = bi.toString(16);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003245 } catch (NoSuchAlgorithmException e) {
Kenny Root3b1abba2010-10-13 15:00:07 -07003246 Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
3247 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
3248 return;
3249 } catch (InvalidKeySpecException e) {
3250 Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
3251 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root38cf8862010-09-26 14:18:51 -07003252 return;
3253 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003254 }
Kenny Root38cf8862010-09-26 14:18:51 -07003255
Kenny Rootaf9d6672010-10-08 09:21:39 -07003256 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003257 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003258 mConnector.execute("obb", "mount", mObbState.canonicalPath, new SensitiveArg(hashedKey),
Jeff Sharkey56cd6462013-06-07 15:09:15 -07003259 mObbState.ownerGid);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003260 } catch (NativeDaemonConnectorException e) {
3261 int code = e.getCode();
3262 if (code != VoldResponseCode.OpFailedStorageBusy) {
3263 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003264 }
3265 }
3266
Kenny Rootaf9d6672010-10-08 09:21:39 -07003267 if (rc == StorageResultCode.OperationSucceeded) {
3268 if (DEBUG_OBB)
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003269 Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003270
3271 synchronized (mObbMounts) {
3272 addObbStateLocked(mObbState);
3273 }
3274
3275 sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
Kenny Root02c87302010-07-01 08:10:18 -07003276 } else {
Kenny Root05105f72010-09-22 17:29:43 -07003277 Slog.e(TAG, "Couldn't mount OBB file: " + rc);
Kenny Roota02b8b02010-08-05 16:14:17 -07003278
Kenny Rootaf9d6672010-10-08 09:21:39 -07003279 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
Kenny Root02c87302010-07-01 08:10:18 -07003280 }
3281 }
3282
Jason parks5af0b912010-11-29 09:05:25 -06003283 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003284 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003285 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root02c87302010-07-01 08:10:18 -07003286 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003287
3288 @Override
3289 public String toString() {
3290 StringBuilder sb = new StringBuilder();
3291 sb.append("MountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003292 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003293 sb.append('}');
3294 return sb.toString();
3295 }
3296 }
3297
3298 class UnmountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003299 private final boolean mForceUnmount;
Kenny Roota02b8b02010-08-05 16:14:17 -07003300
3301 UnmountObbAction(ObbState obbState, boolean force) {
3302 super(obbState);
3303 mForceUnmount = force;
3304 }
3305
Jason parks5af0b912010-11-29 09:05:25 -06003306 @Override
Kenny Root38cf8862010-09-26 14:18:51 -07003307 public void handleExecute() throws IOException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003308 waitForReady();
3309 warnOnNotMounted();
3310
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003311 final ObbState existingState;
Kenny Root38cf8862010-09-26 14:18:51 -07003312 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003313 existingState = mObbPathToStateMap.get(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003314 }
Kenny Root38cf8862010-09-26 14:18:51 -07003315
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003316 if (existingState == null) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003317 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
3318 return;
3319 }
3320
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003321 if (existingState.ownerGid != mObbState.ownerGid) {
3322 Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
3323 + " (owned by GID " + existingState.ownerGid + ")");
Kenny Rootaf9d6672010-10-08 09:21:39 -07003324 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3325 return;
3326 }
3327
Kenny Rootaf9d6672010-10-08 09:21:39 -07003328 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003329 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003330 final Command cmd = new Command("obb", "unmount", mObbState.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08003331 if (mForceUnmount) {
3332 cmd.appendArg("force");
3333 }
3334 mConnector.execute(cmd);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003335 } catch (NativeDaemonConnectorException e) {
3336 int code = e.getCode();
3337 if (code == VoldResponseCode.OpFailedStorageBusy) {
3338 rc = StorageResultCode.OperationFailedStorageBusy;
3339 } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
3340 // If it's not mounted then we've already won.
3341 rc = StorageResultCode.OperationSucceeded;
3342 } else {
3343 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003344 }
3345 }
3346
Kenny Rootaf9d6672010-10-08 09:21:39 -07003347 if (rc == StorageResultCode.OperationSucceeded) {
3348 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003349 removeObbStateLocked(existingState);
Kenny Root38cf8862010-09-26 14:18:51 -07003350 }
3351
Kenny Rootaf9d6672010-10-08 09:21:39 -07003352 sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
Kenny Roota02b8b02010-08-05 16:14:17 -07003353 } else {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003354 Slog.w(TAG, "Could not unmount OBB: " + existingState);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003355 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
Kenny Roota02b8b02010-08-05 16:14:17 -07003356 }
3357 }
3358
Jason parks5af0b912010-11-29 09:05:25 -06003359 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003360 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003361 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Roota02b8b02010-08-05 16:14:17 -07003362 }
3363
3364 @Override
3365 public String toString() {
3366 StringBuilder sb = new StringBuilder();
3367 sb.append("UnmountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003368 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003369 sb.append(",force=");
3370 sb.append(mForceUnmount);
Kenny Roota02b8b02010-08-05 16:14:17 -07003371 sb.append('}');
3372 return sb.toString();
3373 }
Kenny Root02c87302010-07-01 08:10:18 -07003374 }
Kenny Root38cf8862010-09-26 14:18:51 -07003375
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003376 private static class Callbacks extends Handler {
3377 private static final int MSG_STORAGE_STATE_CHANGED = 1;
3378 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003379 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
3380 private static final int MSG_VOLUME_FORGOTTEN = 4;
3381 private static final int MSG_DISK_SCANNED = 5;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003382 private static final int MSG_DISK_DESTROYED = 6;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003383
3384 private final RemoteCallbackList<IMountServiceListener>
3385 mCallbacks = new RemoteCallbackList<>();
3386
3387 public Callbacks(Looper looper) {
3388 super(looper);
3389 }
3390
3391 public void register(IMountServiceListener callback) {
3392 mCallbacks.register(callback);
3393 }
3394
3395 public void unregister(IMountServiceListener callback) {
3396 mCallbacks.unregister(callback);
3397 }
3398
3399 @Override
3400 public void handleMessage(Message msg) {
3401 final SomeArgs args = (SomeArgs) msg.obj;
3402 final int n = mCallbacks.beginBroadcast();
3403 for (int i = 0; i < n; i++) {
3404 final IMountServiceListener callback = mCallbacks.getBroadcastItem(i);
3405 try {
3406 invokeCallback(callback, msg.what, args);
3407 } catch (RemoteException ignored) {
3408 }
3409 }
3410 mCallbacks.finishBroadcast();
3411 args.recycle();
3412 }
3413
3414 private void invokeCallback(IMountServiceListener callback, int what, SomeArgs args)
3415 throws RemoteException {
3416 switch (what) {
3417 case MSG_STORAGE_STATE_CHANGED: {
3418 callback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
3419 (String) args.arg3);
3420 break;
3421 }
3422 case MSG_VOLUME_STATE_CHANGED: {
3423 callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
3424 break;
3425 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07003426 case MSG_VOLUME_RECORD_CHANGED: {
3427 callback.onVolumeRecordChanged((VolumeRecord) args.arg1);
3428 break;
3429 }
3430 case MSG_VOLUME_FORGOTTEN: {
3431 callback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003432 break;
3433 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003434 case MSG_DISK_SCANNED: {
3435 callback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003436 break;
3437 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003438 case MSG_DISK_DESTROYED: {
3439 callback.onDiskDestroyed((DiskInfo) args.arg1);
3440 break;
3441 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003442 }
3443 }
3444
3445 private void notifyStorageStateChanged(String path, String oldState, String newState) {
3446 final SomeArgs args = SomeArgs.obtain();
3447 args.arg1 = path;
3448 args.arg2 = oldState;
3449 args.arg3 = newState;
3450 obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
3451 }
3452
3453 private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
3454 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003455 args.arg1 = vol.clone();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003456 args.argi2 = oldState;
3457 args.argi3 = newState;
3458 obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
3459 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003460
Jeff Sharkey50a05452015-04-29 11:24:52 -07003461 private void notifyVolumeRecordChanged(VolumeRecord rec) {
3462 final SomeArgs args = SomeArgs.obtain();
3463 args.arg1 = rec.clone();
3464 obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
3465 }
3466
3467 private void notifyVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003468 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003469 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003470 obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003471 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003472
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003473 private void notifyDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003474 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003475 args.arg1 = disk.clone();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003476 args.argi2 = volumeCount;
3477 obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003478 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003479
3480 private void notifyDiskDestroyed(DiskInfo disk) {
3481 final SomeArgs args = SomeArgs.obtain();
3482 args.arg1 = disk.clone();
3483 obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
3484 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003485 }
3486
Kenny Root38cf8862010-09-26 14:18:51 -07003487 @Override
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003488 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
3489 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
3490
3491 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003492 synchronized (mLock) {
3493 pw.println("Disks:");
3494 pw.increaseIndent();
3495 for (int i = 0; i < mDisks.size(); i++) {
3496 final DiskInfo disk = mDisks.valueAt(i);
3497 disk.dump(pw);
3498 }
3499 pw.decreaseIndent();
3500
3501 pw.println();
3502 pw.println("Volumes:");
3503 pw.increaseIndent();
3504 for (int i = 0; i < mVolumes.size(); i++) {
3505 final VolumeInfo vol = mVolumes.valueAt(i);
3506 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue;
3507 vol.dump(pw);
3508 }
3509 pw.decreaseIndent();
3510
3511 pw.println();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003512 pw.println("Records:");
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003513 pw.increaseIndent();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003514 for (int i = 0; i < mRecords.size(); i++) {
3515 final VolumeRecord note = mRecords.valueAt(i);
3516 note.dump(pw);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003517 }
3518 pw.decreaseIndent();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07003519
3520 pw.println();
3521 pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07003522 pw.println("Force adoptable: " + mForceAdoptable);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08003523 pw.println();
3524 pw.println("Started users: " + Arrays.toString(mStartedUsers));
3525 pw.println("Unlocked users: " + Arrays.toString(mUnlockedUsers));
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003526 }
Kenny Root38cf8862010-09-26 14:18:51 -07003527
Kenny Root38cf8862010-09-26 14:18:51 -07003528 synchronized (mObbMounts) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003529 pw.println();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003530 pw.println("mObbMounts:");
3531 pw.increaseIndent();
3532 final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet()
3533 .iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003534 while (binders.hasNext()) {
3535 Entry<IBinder, List<ObbState>> e = binders.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003536 pw.println(e.getKey() + ":");
3537 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003538 final List<ObbState> obbStates = e.getValue();
Kenny Root38cf8862010-09-26 14:18:51 -07003539 for (final ObbState obbState : obbStates) {
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003540 pw.println(obbState);
Kenny Root38cf8862010-09-26 14:18:51 -07003541 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003542 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003543 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003544 pw.decreaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003545
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003546 pw.println();
3547 pw.println("mObbPathToStateMap:");
3548 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003549 final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
3550 while (maps.hasNext()) {
3551 final Entry<String, ObbState> e = maps.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003552 pw.print(e.getKey());
3553 pw.print(" -> ");
3554 pw.println(e.getValue());
Kenny Rootaf9d6672010-10-08 09:21:39 -07003555 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003556 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003557 }
Kenny Root4161f9b2011-07-13 09:48:33 -07003558
Robert Greenwalt470fd722012-01-18 12:51:15 -08003559 pw.println();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003560 pw.println("mConnection:");
3561 pw.increaseIndent();
Robert Greenwalt470fd722012-01-18 12:51:15 -08003562 mConnector.dump(fd, pw, args);
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003563 pw.decreaseIndent();
Christopher Tate7265abe2014-11-21 13:54:45 -08003564
Christopher Tate7265abe2014-11-21 13:54:45 -08003565 pw.println();
3566 pw.print("Last maintenance: ");
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07003567 pw.println(TimeUtils.formatForLogging(mLastMaintenance));
Kenny Root38cf8862010-09-26 14:18:51 -07003568 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003569
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003570 /** {@inheritDoc} */
Jeff Sharkey48877892015-03-18 11:27:19 -07003571 @Override
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003572 public void monitor() {
3573 if (mConnector != null) {
3574 mConnector.monitor();
3575 }
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07003576 if (mCryptConnector != null) {
3577 mCryptConnector.monitor();
3578 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003579 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003580
3581 private final class MountServiceInternalImpl extends MountServiceInternal {
3582 // Not guarded by a lock.
3583 private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
3584 new CopyOnWriteArrayList<>();
3585
3586 @Override
3587 public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
3588 // No locking - CopyOnWriteArrayList
3589 mPolicies.add(policy);
3590 }
3591
3592 @Override
3593 public void onExternalStoragePolicyChanged(int uid, String packageName) {
3594 final int mountMode = getExternalStorageMountMode(uid, packageName);
3595 remountUidExternalStorage(uid, mountMode);
3596 }
3597
3598 @Override
3599 public int getExternalStorageMountMode(int uid, String packageName) {
3600 // No locking - CopyOnWriteArrayList
3601 int mountMode = Integer.MAX_VALUE;
3602 for (ExternalStorageMountPolicy policy : mPolicies) {
3603 final int policyMode = policy.getMountMode(uid, packageName);
3604 if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
3605 return Zygote.MOUNT_EXTERNAL_NONE;
3606 }
3607 mountMode = Math.min(mountMode, policyMode);
3608 }
3609 if (mountMode == Integer.MAX_VALUE) {
3610 return Zygote.MOUNT_EXTERNAL_NONE;
3611 }
3612 return mountMode;
3613 }
3614
3615 public boolean hasExternalStorage(int uid, String packageName) {
Amith Yamasani2bd5cff2015-07-22 14:42:31 -07003616 // No need to check for system uid. This avoids a deadlock between
3617 // PackageManagerService and AppOpsService.
3618 if (uid == Process.SYSTEM_UID) {
3619 return true;
3620 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003621 // No locking - CopyOnWriteArrayList
3622 for (ExternalStorageMountPolicy policy : mPolicies) {
3623 final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
3624 if (!policyHasStorage) {
3625 return false;
3626 }
3627 }
3628 return true;
3629 }
3630 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003631}