blob: 55d31c39fd736c392fba20637bc54d017f7c9154 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Jeff Sharkey4c099d02015-05-15 13:45:00 -070019import static com.android.internal.util.XmlUtils.readBooleanAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070020import static com.android.internal.util.XmlUtils.readIntAttribute;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070021import static com.android.internal.util.XmlUtils.readLongAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070022import static com.android.internal.util.XmlUtils.readStringAttribute;
Jeff Sharkey4c099d02015-05-15 13:45:00 -070023import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070024import static com.android.internal.util.XmlUtils.writeIntAttribute;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070025import static com.android.internal.util.XmlUtils.writeLongAttribute;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070026import static com.android.internal.util.XmlUtils.writeStringAttribute;
Jeff Sharkey5217cac2015-12-20 15:34:01 -070027
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070028import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
29import static org.xmlpull.v1.XmlPullParser.START_TAG;
30
Jason parks8888c592011-01-20 22:46:41 -060031import android.Manifest;
Jeff Sharkeyef10ee02015-07-05 14:17:27 -070032import android.annotation.Nullable;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -070033import android.app.ActivityManager;
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;
Felipe Leme281389a2016-10-10 17:12:20 -070048import android.net.TrafficStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.net.Uri;
Kenny Root02c87302010-07-01 08:10:18 -070050import android.os.Binder;
Jeff Sharkey4c099d02015-05-15 13:45:00 -070051import android.os.DropBoxManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070052import android.os.Environment;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070053import android.os.Environment.UserEnvironment;
Jeff Sharkey48877892015-03-18 11:27:19 -070054import android.os.FileUtils;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080055import android.os.Handler;
Dianne Hackbornefa92b22013-05-03 14:11:43 -070056import android.os.HandlerThread;
Kenny Roota02b8b02010-08-05 16:14:17 -070057import android.os.IBinder;
Daniel Sandler5f27ef42010-03-16 15:42:02 -040058import android.os.Looper;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080059import android.os.Message;
Daichi Hirono9e8d9e22015-11-13 14:37:00 +090060import android.os.ParcelFileDescriptor;
Jeff Sharkeyce14cd02015-12-07 15:35:42 -070061import android.os.PowerManager;
Jeff Sharkey9527b222015-06-24 15:24:48 -070062import android.os.Process;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070063import android.os.RemoteCallbackList;
San Mehat4270e1e2010-01-29 05:32:19 -080064import android.os.RemoteException;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -080065import android.os.ServiceManager;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -070066import android.os.SystemClock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070068import android.os.UserHandle;
Emily Bernier92aa5a22014-07-07 10:11:48 -040069import android.os.UserManager;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070070import android.os.storage.DiskInfo;
Sudheer Shanka2250d562016-11-07 15:41:02 -080071import android.os.storage.IStorageEventListener;
72import android.os.storage.IStorageShutdownObserver;
Kenny Roota02b8b02010-08-05 16:14:17 -070073import android.os.storage.IObbActionListener;
Sudheer Shanka2250d562016-11-07 15:41:02 -080074import android.os.storage.IStorageManager;
75import android.os.storage.StorageManagerInternal;
Kenny Rootaf9d6672010-10-08 09:21:39 -070076import android.os.storage.OnObbStateChangeListener;
Paul Lawrence46791e72014-04-03 09:10:26 -070077import android.os.storage.StorageManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070078import android.os.storage.StorageResultCode;
Mike Lockwood2f6a3882011-05-09 19:08:06 -070079import android.os.storage.StorageVolume;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070080import android.os.storage.VolumeInfo;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070081import android.os.storage.VolumeRecord;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070082import android.provider.MediaStore;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070083import android.provider.Settings;
Jason parksf7b3cd42011-01-27 09:28:25 -060084import android.text.TextUtils;
Jeff Sharkey1783f142015-04-17 10:52:51 -070085import android.text.format.DateUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -070086import android.util.ArrayMap;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070087import android.util.AtomicFile;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070088import android.util.Log;
Felipe Leme281389a2016-10-10 17:12:20 -070089import android.util.Pair;
San Mehata5078592010-03-25 09:36:54 -070090import android.util.Slog;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070091import android.util.TimeUtils;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070092import android.util.Xml;
Jeff Sharkey48877892015-03-18 11:27:19 -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 Sharkeyb9fe5372015-12-03 15:23:08 -0700103import com.android.internal.widget.LockPatternUtils;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700104import com.android.server.NativeDaemonConnector.Command;
Jeff Sharkey56cd6462013-06-07 15:09:15 -0700105import com.android.server.NativeDaemonConnector.SensitiveArg;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700106import com.android.server.pm.PackageManagerService;
Kenny Roota02b8b02010-08-05 16:14:17 -0700107
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700108import libcore.io.IoUtils;
109import libcore.util.EmptyArray;
110
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700111import org.xmlpull.v1.XmlPullParser;
112import org.xmlpull.v1.XmlPullParserException;
113import org.xmlpull.v1.XmlSerializer;
114
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700115import java.io.File;
Kenny Root38cf8862010-09-26 14:18:51 -0700116import java.io.FileDescriptor;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700117import java.io.FileInputStream;
118import java.io.FileNotFoundException;
Christopher Tate7265abe2014-11-21 13:54:45 -0800119import java.io.FileOutputStream;
Kenny Root05105f72010-09-22 17:29:43 -0700120import java.io.IOException;
Kenny Root38cf8862010-09-26 14:18:51 -0700121import java.io.PrintWriter;
Kenny Root3b1abba2010-10-13 15:00:07 -0700122import java.math.BigInteger;
Paul Lawrence8e397362014-01-27 15:22:30 -0800123import java.nio.charset.StandardCharsets;
Kenny Root735de3b2010-09-30 14:11:39 -0700124import java.security.NoSuchAlgorithmException;
Kenny Root3b1abba2010-10-13 15:00:07 -0700125import java.security.spec.InvalidKeySpecException;
126import java.security.spec.KeySpec;
San Mehat22dd86e2010-01-12 12:21:18 -0800127import java.util.ArrayList;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800128import java.util.Arrays;
Kenny Roota02b8b02010-08-05 16:14:17 -0700129import java.util.HashMap;
San Mehat6cdd9c02010-02-09 14:45:20 -0800130import java.util.HashSet;
Kenny Root38cf8862010-09-26 14:18:51 -0700131import java.util.Iterator;
Kenny Roota02b8b02010-08-05 16:14:17 -0700132import java.util.LinkedList;
133import java.util.List;
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700134import java.util.Locale;
Kenny Roota02b8b02010-08-05 16:14:17 -0700135import java.util.Map;
Kenny Root38cf8862010-09-26 14:18:51 -0700136import java.util.Map.Entry;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700137import java.util.Objects;
Svet Ganov6ee871e2015-07-10 14:29:33 -0700138import java.util.concurrent.CopyOnWriteArrayList;
Kenny Root51a573c2012-05-17 13:30:28 -0700139import java.util.concurrent.CountDownLatch;
140import java.util.concurrent.TimeUnit;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700141import java.util.concurrent.TimeoutException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142
Kenny Root3b1abba2010-10-13 15:00:07 -0700143import javax.crypto.SecretKey;
144import javax.crypto.SecretKeyFactory;
145import javax.crypto.spec.PBEKeySpec;
146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147/**
Jeff Sharkey48877892015-03-18 11:27:19 -0700148 * Service responsible for various storage media. Connects to {@code vold} to
149 * watch for and manage dynamically added storage, such as SD cards and USB mass
150 * storage. Also decides how storage should be presented to users on the device.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 */
Sudheer Shanka2250d562016-11-07 15:41:02 -0800152class StorageManagerService extends IStorageManager.Stub
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700153 implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
Jason parks5af0b912010-11-29 09:05:25 -0600154
Christopher Tated417d622013-08-19 16:14:25 -0700155 // Static direct instance pointer for the tightly-coupled idle service to use
Sudheer Shanka2250d562016-11-07 15:41:02 -0800156 static StorageManagerService sSelf = null;
Christopher Tated417d622013-08-19 16:14:25 -0700157
Jeff Sharkey56e62932015-03-21 20:41:00 -0700158 public static class Lifecycle extends SystemService {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800159 private StorageManagerService mStorageManagerService;
Jeff Sharkey56e62932015-03-21 20:41:00 -0700160
161 public Lifecycle(Context context) {
162 super(context);
163 }
164
165 @Override
166 public void onStart() {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800167 mStorageManagerService = new StorageManagerService(getContext());
168 publishBinderService("mount", mStorageManagerService);
169 mStorageManagerService.start();
Jeff Sharkey56e62932015-03-21 20:41:00 -0700170 }
171
172 @Override
173 public void onBootPhase(int phase) {
174 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800175 mStorageManagerService.systemReady();
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900176 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800177 mStorageManagerService.bootCompleted();
Jeff Sharkey56e62932015-03-21 20:41:00 -0700178 }
179 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700180
181 @Override
Jeff Sharkeyab15c392016-05-05 11:45:01 -0600182 public void onSwitchUser(int userHandle) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800183 mStorageManagerService.mCurrentUserId = userHandle;
Jeff Sharkeyab15c392016-05-05 11:45:01 -0600184 }
185
186 @Override
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700187 public void onUnlockUser(int userHandle) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800188 mStorageManagerService.onUnlockUser(userHandle);
Jeff Sharkey48877892015-03-18 11:27:19 -0700189 }
190
191 @Override
192 public void onCleanupUser(int userHandle) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800193 mStorageManagerService.onCleanupUser(userHandle);
Jeff Sharkey48877892015-03-18 11:27:19 -0700194 }
Jeff Sharkey56e62932015-03-21 20:41:00 -0700195 }
196
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800197 private static final boolean DEBUG_EVENTS = false;
Kenny Rootb7db2722011-01-25 16:39:35 -0800198 private static final boolean DEBUG_OBB = false;
Kenny Root02c87302010-07-01 08:10:18 -0700199
Kenny Root07714d42011-08-17 17:49:28 -0700200 // Disable this since it messes up long-running cryptfs operations.
201 private static final boolean WATCHDOG_ENABLE = false;
202
Jeff Sharkey00455bf2016-11-04 14:45:24 -0600203 /**
204 * Our goal is for all Android devices to be usable as development devices,
205 * which includes the new Direct Boot mode added in N. For devices that
206 * don't have native FBE support, we offer an emulation mode for developer
207 * testing purposes, but if it's prohibitively difficult to support this
208 * mode, it can be disabled for specific products using this flag.
209 */
210 private static final boolean EMULATE_FBE_SUPPORTED = true;
211
Sudheer Shanka2250d562016-11-07 15:41:02 -0800212 private static final String TAG = "StorageManagerService";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700213
Jeff Sharkey9756d752015-05-14 21:07:42 -0700214 private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700215 private static final String TAG_STORAGE_TRIM = "storage_trim";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216
Kenny Root305bcbf2010-09-03 07:56:38 -0700217 private static final String VOLD_TAG = "VoldConnector";
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700218 private static final String CRYPTD_TAG = "CryptdConnector";
Kenny Root305bcbf2010-09-03 07:56:38 -0700219
Kenny Rootcf0b38c2011-03-22 14:17:59 -0700220 /** Maximum number of ASEC containers allowed to be mounted. */
221 private static final int MAX_CONTAINERS = 250;
222
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700223 /** Magic value sent by MoveTask.cpp */
224 private static final int MOVE_STATUS_COPY_FINISHED = 82;
225
San Mehat4270e1e2010-01-29 05:32:19 -0800226 /*
227 * Internal vold response code constants
228 */
San Mehat22dd86e2010-01-12 12:21:18 -0800229 class VoldResponseCode {
San Mehat4270e1e2010-01-29 05:32:19 -0800230 /*
231 * 100 series - Requestion action was initiated; expect another reply
232 * before proceeding with a new command.
233 */
San Mehat22dd86e2010-01-12 12:21:18 -0800234 public static final int VolumeListResult = 110;
235 public static final int AsecListResult = 111;
San Mehatc1b4ce92010-02-16 17:13:03 -0800236 public static final int StorageUsersListResult = 112;
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700237 public static final int CryptfsGetfieldResult = 113;
San Mehat22dd86e2010-01-12 12:21:18 -0800238
San Mehat4270e1e2010-01-29 05:32:19 -0800239 /*
240 * 200 series - Requestion action has been successfully completed.
241 */
242 public static final int ShareStatusResult = 210;
San Mehat22dd86e2010-01-12 12:21:18 -0800243 public static final int AsecPathResult = 211;
San Mehat4270e1e2010-01-29 05:32:19 -0800244 public static final int ShareEnabledResult = 212;
San Mehat22dd86e2010-01-12 12:21:18 -0800245
San Mehat4270e1e2010-01-29 05:32:19 -0800246 /*
247 * 400 series - Command was accepted, but the requested action
248 * did not take place.
249 */
250 public static final int OpFailedNoMedia = 401;
251 public static final int OpFailedMediaBlank = 402;
252 public static final int OpFailedMediaCorrupt = 403;
253 public static final int OpFailedVolNotMounted = 404;
San Mehatd9709982010-02-18 11:43:03 -0800254 public static final int OpFailedStorageBusy = 405;
San Mehat2d66cef2010-03-23 11:12:52 -0700255 public static final int OpFailedStorageNotFound = 406;
San Mehat4270e1e2010-01-29 05:32:19 -0800256
257 /*
258 * 600 series - Unsolicited broadcasts.
259 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700260 public static final int DISK_CREATED = 640;
261 public static final int DISK_SIZE_CHANGED = 641;
262 public static final int DISK_LABEL_CHANGED = 642;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700263 public static final int DISK_SCANNED = 643;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700264 public static final int DISK_SYS_PATH_CHANGED = 644;
Jeff Sharkey48877892015-03-18 11:27:19 -0700265 public static final int DISK_DESTROYED = 649;
266
267 public static final int VOLUME_CREATED = 650;
268 public static final int VOLUME_STATE_CHANGED = 651;
269 public static final int VOLUME_FS_TYPE_CHANGED = 652;
270 public static final int VOLUME_FS_UUID_CHANGED = 653;
271 public static final int VOLUME_FS_LABEL_CHANGED = 654;
272 public static final int VOLUME_PATH_CHANGED = 655;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700273 public static final int VOLUME_INTERNAL_PATH_CHANGED = 656;
Jeff Sharkey48877892015-03-18 11:27:19 -0700274 public static final int VOLUME_DESTROYED = 659;
Svetoslavf23b64d2013-04-25 14:45:54 -0700275
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700276 public static final int MOVE_STATUS = 660;
Jeff Sharkey9756d752015-05-14 21:07:42 -0700277 public static final int BENCHMARK_RESULT = 661;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700278 public static final int TRIM_RESULT = 662;
San Mehat22dd86e2010-01-12 12:21:18 -0800279 }
280
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700281 private static final int VERSION_INIT = 1;
282 private static final int VERSION_ADD_PRIMARY = 2;
Jeff Sharkeyfced5342015-05-10 14:53:34 -0700283 private static final int VERSION_FIX_PRIMARY = 3;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700284
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700285 private static final String TAG_VOLUMES = "volumes";
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700286 private static final String ATTR_VERSION = "version";
287 private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid";
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700288 private static final String ATTR_FORCE_ADOPTABLE = "forceAdoptable";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700289 private static final String TAG_VOLUME = "volume";
290 private static final String ATTR_TYPE = "type";
291 private static final String ATTR_FS_UUID = "fsUuid";
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700292 private static final String ATTR_PART_GUID = "partGuid";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700293 private static final String ATTR_NICKNAME = "nickname";
294 private static final String ATTR_USER_FLAGS = "userFlags";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700295 private static final String ATTR_CREATED_MILLIS = "createdMillis";
296 private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis";
297 private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700298
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700299 private final AtomicFile mSettingsFile;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700300
Jeff Sharkey48877892015-03-18 11:27:19 -0700301 /**
302 * <em>Never</em> hold the lock while performing downcalls into vold, since
303 * unsolicited events can suddenly appear to update data structures.
304 */
305 private final Object mLock = new Object();
306
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700307 /** Set of users that we know are unlocked. */
Jeff Sharkey48877892015-03-18 11:27:19 -0700308 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700309 private int[] mLocalUnlockedUsers = EmptyArray.INT;
310 /** Set of users that system knows are unlocked. */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800311 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700312 private int[] mSystemUnlockedUsers = EmptyArray.INT;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700313
314 /** Map from disk ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700315 @GuardedBy("mLock")
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700316 private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700317 /** Map from volume ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700318 @GuardedBy("mLock")
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700319 private final ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
Jeff Sharkey48877892015-03-18 11:27:19 -0700320
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700321 /** Map from UUID to record */
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700322 @GuardedBy("mLock")
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700323 private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>();
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700324 @GuardedBy("mLock")
325 private String mPrimaryStorageUuid;
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700326 @GuardedBy("mLock")
327 private boolean mForceAdoptable;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700328
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700329 /** Map from disk ID to latches */
330 @GuardedBy("mLock")
331 private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
332
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700333 @GuardedBy("mLock")
334 private IPackageMoveObserver mMoveCallback;
335 @GuardedBy("mLock")
336 private String mMoveTargetUuid;
337
Jeff Sharkeyab15c392016-05-05 11:45:01 -0600338 private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
339
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700340 private VolumeInfo findVolumeByIdOrThrow(String id) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700341 synchronized (mLock) {
342 final VolumeInfo vol = mVolumes.get(id);
343 if (vol != null) {
344 return vol;
345 }
346 }
347 throw new IllegalArgumentException("No volume found for ID " + id);
348 }
349
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700350 private String findVolumeIdForPathOrThrow(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700351 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700352 for (int i = 0; i < mVolumes.size(); i++) {
353 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700354 if (vol.path != null && path.startsWith(vol.path)) {
355 return vol.id;
Jeff Sharkey48877892015-03-18 11:27:19 -0700356 }
357 }
358 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700359 throw new IllegalArgumentException("No volume found for path " + path);
Jeff Sharkey48877892015-03-18 11:27:19 -0700360 }
361
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700362 private VolumeRecord findRecordForPath(String path) {
363 synchronized (mLock) {
364 for (int i = 0; i < mVolumes.size(); i++) {
365 final VolumeInfo vol = mVolumes.valueAt(i);
366 if (vol.path != null && path.startsWith(vol.path)) {
367 return mRecords.get(vol.fsUuid);
368 }
369 }
370 }
371 return null;
372 }
373
374 private String scrubPath(String path) {
375 if (path.startsWith(Environment.getDataDirectory().getAbsolutePath())) {
376 return "internal";
377 }
378 final VolumeRecord rec = findRecordForPath(path);
379 if (rec == null || rec.createdMillis == 0) {
380 return "unknown";
381 } else {
382 return "ext:" + (int) ((System.currentTimeMillis() - rec.createdMillis)
383 / DateUtils.WEEK_IN_MILLIS) + "w";
384 }
385 }
386
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700387 private @Nullable VolumeInfo findStorageForUuid(String volumeUuid) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700388 final StorageManager storage = mContext.getSystemService(StorageManager.class);
389 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700390 return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL);
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700391 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
392 return storage.getPrimaryPhysicalVolume();
393 } else {
394 return storage.findEmulatedForPrivate(storage.findVolumeByUuid(volumeUuid));
395 }
396 }
397
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700398 private boolean shouldBenchmark() {
399 final long benchInterval = Settings.Global.getLong(mContext.getContentResolver(),
400 Settings.Global.STORAGE_BENCHMARK_INTERVAL, DateUtils.WEEK_IN_MILLIS);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700401 if (benchInterval == -1) {
402 return false;
403 } else if (benchInterval == 0) {
404 return true;
405 }
406
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700407 synchronized (mLock) {
408 for (int i = 0; i < mVolumes.size(); i++) {
409 final VolumeInfo vol = mVolumes.valueAt(i);
410 final VolumeRecord rec = mRecords.get(vol.fsUuid);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700411 if (vol.isMountedWritable() && rec != null) {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700412 final long benchAge = System.currentTimeMillis() - rec.lastBenchMillis;
413 if (benchAge >= benchInterval) {
414 return true;
415 }
416 }
417 }
418 return false;
419 }
420 }
421
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700422 private CountDownLatch findOrCreateDiskScanLatch(String diskId) {
423 synchronized (mLock) {
424 CountDownLatch latch = mDiskScanLatches.get(diskId);
425 if (latch == null) {
426 latch = new CountDownLatch(1);
427 mDiskScanLatches.put(diskId, latch);
428 }
429 return latch;
430 }
431 }
432
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800433 private static String escapeNull(String arg) {
434 if (TextUtils.isEmpty(arg)) {
435 return "!";
436 } else {
437 if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
438 throw new IllegalArgumentException(arg);
439 }
440 return arg;
441 }
442 }
443
Paul Lawrence8e397362014-01-27 15:22:30 -0800444 /** List of crypto types.
445 * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
446 * corresponding commands in CommandListener.cpp */
447 public static final String[] CRYPTO_TYPES
448 = { "password", "default", "pattern", "pin" };
449
Brian Carlstrom7395a8a2014-04-28 22:11:01 -0700450 private final Context mContext;
Jeff Sharkeycd575992016-03-29 14:12:49 -0600451
Brian Carlstromdfad99a2014-05-07 15:21:14 -0700452 private final NativeDaemonConnector mConnector;
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700453 private final NativeDaemonConnector mCryptConnector;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700454
Jeff Sharkeycd575992016-03-29 14:12:49 -0600455 private final Thread mConnectorThread;
456 private final Thread mCryptConnectorThread;
457
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700458 private volatile boolean mSystemReady = false;
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900459 private volatile boolean mBootCompleted = false;
Jeff Sharkey48877892015-03-18 11:27:19 -0700460 private volatile boolean mDaemonConnected = false;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700461
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700462 private PackageManagerService mPms;
463
464 private final Callbacks mCallbacks;
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700465 private final LockPatternUtils mLockPatternUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -0700466
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700467 // Two connectors - mConnector & mCryptConnector
468 private final CountDownLatch mConnectedSignal = new CountDownLatch(2);
Jeff Sharkey0be607c2012-11-14 14:39:19 -0800469 private final CountDownLatch mAsecsScanned = new CountDownLatch(1);
Jeff Sharkey48877892015-03-18 11:27:19 -0700470
471 private final Object mUnmountLock = new Object();
472 @GuardedBy("mUnmountLock")
473 private CountDownLatch mUnmountSignal;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800474
San Mehat6cdd9c02010-02-09 14:45:20 -0800475 /**
476 * Private hash of currently mounted secure containers.
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800477 * Used as a lock in methods to manipulate secure containers.
San Mehat6cdd9c02010-02-09 14:45:20 -0800478 */
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800479 final private HashSet<String> mAsecMountSet = new HashSet<String>();
San Mehat6cdd9c02010-02-09 14:45:20 -0800480
Kenny Root02c87302010-07-01 08:10:18 -0700481 /**
Kenny Root3b1abba2010-10-13 15:00:07 -0700482 * The size of the crypto algorithm key in bits for OBB files. Currently
483 * Twofish is used which takes 128-bit keys.
484 */
485 private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
486
487 /**
488 * The number of times to run SHA1 in the PBKDF2 function for OBB files.
489 * 1024 is reasonably secure and not too slow.
490 */
491 private static final int PBKDF2_HASH_ROUNDS = 1024;
492
493 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700494 * Mounted OBB tracking information. Used to track the current state of all
495 * OBBs.
Kenny Root02c87302010-07-01 08:10:18 -0700496 */
Kenny Root735de3b2010-09-30 14:11:39 -0700497 final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700498
499 /** Map from raw paths to {@link ObbState}. */
Kenny Roota02b8b02010-08-05 16:14:17 -0700500 final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
501
Svet Ganov6ee871e2015-07-10 14:29:33 -0700502 // Not guarded by a lock.
Sudheer Shanka2250d562016-11-07 15:41:02 -0800503 private final StorageManagerInternalImpl mStorageManagerInternal
504 = new StorageManagerInternalImpl();
Svet Ganov6ee871e2015-07-10 14:29:33 -0700505
Kenny Roota02b8b02010-08-05 16:14:17 -0700506 class ObbState implements IBinder.DeathRecipient {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700507 public ObbState(String rawPath, String canonicalPath, int callingUid,
508 IObbActionListener token, int nonce) {
509 this.rawPath = rawPath;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700510 this.canonicalPath = canonicalPath;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700511
512 this.ownerGid = UserHandle.getSharedAppGid(callingUid);
Kenny Rootaf9d6672010-10-08 09:21:39 -0700513 this.token = token;
514 this.nonce = nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700515 }
516
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700517 final String rawPath;
518 final String canonicalPath;
Kenny Roota02b8b02010-08-05 16:14:17 -0700519
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700520 final int ownerGid;
Kenny Roota02b8b02010-08-05 16:14:17 -0700521
Kenny Rootaf9d6672010-10-08 09:21:39 -0700522 // Token of remote Binder caller
523 final IObbActionListener token;
524
525 // Identifier to pass back to the token
526 final int nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700527
Kenny Root735de3b2010-09-30 14:11:39 -0700528 public IBinder getBinder() {
529 return token.asBinder();
530 }
531
Kenny Roota02b8b02010-08-05 16:14:17 -0700532 @Override
533 public void binderDied() {
534 ObbAction action = new UnmountObbAction(this, true);
535 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root735de3b2010-09-30 14:11:39 -0700536 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700537
Kenny Root5919ac62010-10-05 09:49:40 -0700538 public void link() throws RemoteException {
539 getBinder().linkToDeath(this, 0);
540 }
541
542 public void unlink() {
Kenny Root735de3b2010-09-30 14:11:39 -0700543 getBinder().unlinkToDeath(this, 0);
Kenny Roota02b8b02010-08-05 16:14:17 -0700544 }
Kenny Root38cf8862010-09-26 14:18:51 -0700545
546 @Override
547 public String toString() {
548 StringBuilder sb = new StringBuilder("ObbState{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700549 sb.append("rawPath=").append(rawPath);
550 sb.append(",canonicalPath=").append(canonicalPath);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700551 sb.append(",ownerGid=").append(ownerGid);
552 sb.append(",token=").append(token);
553 sb.append(",binder=").append(getBinder());
Kenny Root38cf8862010-09-26 14:18:51 -0700554 sb.append('}');
555 return sb.toString();
556 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700557 }
558
559 // OBB Action Handler
560 final private ObbActionHandler mObbActionHandler;
561
562 // OBB action handler messages
563 private static final int OBB_RUN_ACTION = 1;
564 private static final int OBB_MCS_BOUND = 2;
565 private static final int OBB_MCS_UNBIND = 3;
566 private static final int OBB_MCS_RECONNECT = 4;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700567 private static final int OBB_FLUSH_MOUNT_STATE = 5;
Kenny Roota02b8b02010-08-05 16:14:17 -0700568
569 /*
570 * Default Container Service information
571 */
572 static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
573 "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
574
575 final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
576
577 class DefaultContainerConnection implements ServiceConnection {
Jeff Sharkey48877892015-03-18 11:27:19 -0700578 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700579 public void onServiceConnected(ComponentName name, IBinder service) {
580 if (DEBUG_OBB)
581 Slog.i(TAG, "onServiceConnected");
582 IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
583 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
584 }
585
Jeff Sharkey48877892015-03-18 11:27:19 -0700586 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700587 public void onServiceDisconnected(ComponentName name) {
588 if (DEBUG_OBB)
589 Slog.i(TAG, "onServiceDisconnected");
590 }
591 };
592
593 // Used in the ObbActionHandler
594 private IMediaContainerService mContainerService = null;
Kenny Root02c87302010-07-01 08:10:18 -0700595
Christopher Tate7265abe2014-11-21 13:54:45 -0800596 // Last fstrim operation tracking
597 private static final String LAST_FSTRIM_FILE = "last-fstrim";
598 private final File mLastMaintenanceFile;
599 private long mLastMaintenance;
600
Kenny Root02c87302010-07-01 08:10:18 -0700601 // Handler messages
Jeff Sharkey48877892015-03-18 11:27:19 -0700602 private static final int H_SYSTEM_READY = 1;
603 private static final int H_DAEMON_CONNECTED = 2;
604 private static final int H_SHUTDOWN = 3;
605 private static final int H_FSTRIM = 4;
606 private static final int H_VOLUME_MOUNT = 5;
607 private static final int H_VOLUME_BROADCAST = 6;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700608 private static final int H_INTERNAL_BROADCAST = 7;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700609 private static final int H_VOLUME_UNMOUNT = 8;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800610 private static final int H_PARTITION_FORGET = 9;
611 private static final int H_RESET = 10;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800612
Sudheer Shanka2250d562016-11-07 15:41:02 -0800613 class StorageManagerServiceHandler extends Handler {
614 public StorageManagerServiceHandler(Looper looper) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700615 super(looper);
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400616 }
617
Jason parks5af0b912010-11-29 09:05:25 -0600618 @Override
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800619 public void handleMessage(Message msg) {
620 switch (msg.what) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700621 case H_SYSTEM_READY: {
Jeff Sharkey48877892015-03-18 11:27:19 -0700622 handleSystemReady();
623 break;
624 }
625 case H_DAEMON_CONNECTED: {
626 handleDaemonConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700627 break;
628 }
Christopher Tated417d622013-08-19 16:14:25 -0700629 case H_FSTRIM: {
Jeff Sharkey1783f142015-04-17 10:52:51 -0700630 if (!isReady()) {
631 Slog.i(TAG, "fstrim requested, but no daemon connection yet; trying again");
Christopher Tate7618db12015-04-28 16:32:55 -0700632 sendMessageDelayed(obtainMessage(H_FSTRIM, msg.obj),
633 DateUtils.SECOND_IN_MILLIS);
634 break;
Jeff Sharkey1783f142015-04-17 10:52:51 -0700635 }
636
Christopher Tated417d622013-08-19 16:14:25 -0700637 Slog.i(TAG, "Running fstrim idle maintenance");
Christopher Tate7265abe2014-11-21 13:54:45 -0800638
639 // Remember when we kicked it off
640 try {
641 mLastMaintenance = System.currentTimeMillis();
642 mLastMaintenanceFile.setLastModified(mLastMaintenance);
643 } catch (Exception e) {
644 Slog.e(TAG, "Unable to record last fstrim!");
645 }
646
Jeff Sharkey31d0b702016-11-21 14:16:53 -0700647 final int flags = shouldBenchmark() ? StorageManager.FSTRIM_FLAG_BENCHMARK : 0;
648 fstrim(flags);
Christopher Tate7265abe2014-11-21 13:54:45 -0800649
Christopher Tated417d622013-08-19 16:14:25 -0700650 // invoke the completion callback, if any
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700651 // TODO: fstrim is non-blocking, so remove this useless callback
Christopher Tated417d622013-08-19 16:14:25 -0700652 Runnable callback = (Runnable) msg.obj;
653 if (callback != null) {
654 callback.run();
655 }
656 break;
657 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700658 case H_SHUTDOWN: {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800659 final IStorageShutdownObserver obs = (IStorageShutdownObserver) msg.obj;
Jeff Sharkey48877892015-03-18 11:27:19 -0700660 boolean success = false;
661 try {
662 success = mConnector.execute("volume", "shutdown").isClassOk();
663 } catch (NativeDaemonConnectorException ignored) {
664 }
665 if (obs != null) {
666 try {
667 obs.onShutDownComplete(success ? 0 : -1);
668 } catch (RemoteException ignored) {
669 }
670 }
671 break;
672 }
673 case H_VOLUME_MOUNT: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700674 final VolumeInfo vol = (VolumeInfo) msg.obj;
Jeff Sharkey2e606d72015-07-27 14:19:54 -0700675 if (isMountDisallowed(vol)) {
676 Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");
677 break;
678 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700679 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700680 mConnector.execute("volume", "mount", vol.id, vol.mountFlags,
681 vol.mountUserId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700682 } catch (NativeDaemonConnectorException ignored) {
683 }
684 break;
685 }
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700686 case H_VOLUME_UNMOUNT: {
687 final VolumeInfo vol = (VolumeInfo) msg.obj;
688 unmount(vol.getId());
689 break;
690 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700691 case H_VOLUME_BROADCAST: {
692 final StorageVolume userVol = (StorageVolume) msg.obj;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700693 final String envState = userVol.getState();
694 Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + envState + " to "
Jeff Sharkey48877892015-03-18 11:27:19 -0700695 + userVol.getOwner());
696
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700697 final String action = VolumeInfo.getBroadcastForEnvironment(envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700698 if (action != null) {
699 final Intent intent = new Intent(action,
700 Uri.fromFile(userVol.getPathFile()));
701 intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, userVol);
702 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
703 mContext.sendBroadcastAsUser(intent, userVol.getOwner());
704 }
705 break;
706 }
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700707 case H_INTERNAL_BROADCAST: {
708 // Internal broadcasts aimed at system components, not for
709 // third-party apps.
710 final Intent intent = (Intent) msg.obj;
711 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
712 android.Manifest.permission.WRITE_MEDIA_STORAGE);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800713 break;
714 }
715 case H_PARTITION_FORGET: {
716 final String partGuid = (String) msg.obj;
717 forgetPartition(partGuid);
718 break;
719 }
720 case H_RESET: {
721 resetIfReadyAndConnected();
722 break;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700723 }
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800724 }
725 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700726 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700727
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700728 private final Handler mHandler;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800729
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700730 private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
731 @Override
732 public void onReceive(Context context, Intent intent) {
733 final String action = intent.getAction();
734 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700735 Preconditions.checkArgument(userId >= 0);
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700736
737 try {
738 if (Intent.ACTION_USER_ADDED.equals(action)) {
739 final UserManager um = mContext.getSystemService(UserManager.class);
740 final int userSerialNumber = um.getUserSerialNumber(userId);
741 mConnector.execute("volume", "user_added", userId, userSerialNumber);
742 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700743 synchronized (mVolumes) {
744 final int size = mVolumes.size();
745 for (int i = 0; i < size; i++) {
746 final VolumeInfo vol = mVolumes.valueAt(i);
747 if (vol.mountUserId == userId) {
748 vol.mountUserId = UserHandle.USER_NULL;
749 mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
750 }
751 }
752 }
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700753 mConnector.execute("volume", "user_removed", userId);
754 }
755 } catch (NativeDaemonConnectorException e) {
756 Slog.w(TAG, "Failed to send user details to vold", e);
757 }
758 }
759 };
760
Jeff Sharkey56e62932015-03-21 20:41:00 -0700761 @Override
762 public void waitForAsecScan() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700763 waitForLatch(mAsecsScanned, "mAsecsScanned");
Kenny Root51a573c2012-05-17 13:30:28 -0700764 }
765
San Mehat207e5382010-02-04 20:46:54 -0800766 private void waitForReady() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700767 waitForLatch(mConnectedSignal, "mConnectedSignal");
Kenny Root51a573c2012-05-17 13:30:28 -0700768 }
769
Jeff Sharkey48877892015-03-18 11:27:19 -0700770 private void waitForLatch(CountDownLatch latch, String condition) {
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700771 try {
772 waitForLatch(latch, condition, -1);
773 } catch (TimeoutException ignored) {
774 }
775 }
776
777 private void waitForLatch(CountDownLatch latch, String condition, long timeoutMillis)
778 throws TimeoutException {
779 final long startMillis = SystemClock.elapsedRealtime();
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700780 while (true) {
Kenny Root51a573c2012-05-17 13:30:28 -0700781 try {
782 if (latch.await(5000, TimeUnit.MILLISECONDS)) {
San Mehat207e5382010-02-04 20:46:54 -0800783 return;
Kenny Root51a573c2012-05-17 13:30:28 -0700784 } else {
785 Slog.w(TAG, "Thread " + Thread.currentThread().getName()
Jeff Sharkey48877892015-03-18 11:27:19 -0700786 + " still waiting for " + condition + "...");
San Mehat207e5382010-02-04 20:46:54 -0800787 }
Kenny Root51a573c2012-05-17 13:30:28 -0700788 } catch (InterruptedException e) {
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700789 Slog.w(TAG, "Interrupt while waiting for " + condition);
San Mehat207e5382010-02-04 20:46:54 -0800790 }
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700791 if (timeoutMillis > 0 && SystemClock.elapsedRealtime() > startMillis + timeoutMillis) {
792 throw new TimeoutException("Thread " + Thread.currentThread().getName()
793 + " gave up waiting for " + condition + " after " + timeoutMillis + "ms");
794 }
San Mehat207e5382010-02-04 20:46:54 -0800795 }
San Mehat1f6301e2010-01-07 22:40:27 -0800796 }
Kenny Root02c87302010-07-01 08:10:18 -0700797
Paul Lawrence945490c2014-03-27 16:37:28 +0000798 private boolean isReady() {
799 try {
800 return mConnectedSignal.await(0, TimeUnit.MILLISECONDS);
801 } catch (InterruptedException e) {
802 return false;
803 }
804 }
805
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700806 private void handleSystemReady() {
Jeff Sharkey8924e872015-11-30 12:52:10 -0700807 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800808 resetIfReadyAndConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700809
Jeff Sharkey48877892015-03-18 11:27:19 -0700810 // Start scheduling nominally-daily fstrim operations
Christopher Tate115afda2014-06-06 19:06:26 -0700811 MountServiceIdler.scheduleIdlePass(mContext);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700812 }
813
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700814 /**
815 * MediaProvider has a ton of code that makes assumptions about storage
816 * paths never changing, so we outright kill them to pick up new state.
817 */
818 @Deprecated
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700819 private void killMediaProvider(List<UserInfo> users) {
820 if (users == null) return;
821
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700822 final long token = Binder.clearCallingIdentity();
823 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700824 for (UserInfo user : users) {
825 // System user does not have media provider, so skip.
826 if (user.isSystemOnly()) continue;
827
Jeff Sharkey2a9e3f82015-12-18 10:57:58 -0700828 final ProviderInfo provider = mPms.resolveContentProvider(MediaStore.AUTHORITY,
Jeff Sharkey8a372a02016-03-16 16:25:45 -0600829 PackageManager.MATCH_DIRECT_BOOT_AWARE
830 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
831 user.id);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700832 if (provider != null) {
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800833 final IActivityManager am = ActivityManager.getService();
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700834 try {
Jeff Sharkey85f449e2016-06-23 09:26:00 -0600835 am.killApplication(provider.applicationInfo.packageName,
836 UserHandle.getAppId(provider.applicationInfo.uid),
837 UserHandle.USER_ALL, "vold reset");
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700838 // We only need to run this once. It will kill all users' media processes.
839 break;
840 } catch (RemoteException e) {
841 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700842 }
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700843 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700844 } finally {
845 Binder.restoreCallingIdentity(token);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700846 }
847 }
848
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800849 private void addInternalVolumeLocked() {
Amith Yamasania7892482015-08-07 11:09:05 -0700850 // Create a stub volume that represents internal storage
851 final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
852 VolumeInfo.TYPE_PRIVATE, null, null);
853 internal.state = VolumeInfo.STATE_MOUNTED;
854 internal.path = Environment.getDataDirectory().getAbsolutePath();
855 mVolumes.put(internal.id, internal);
856 }
857
Jeff Sharkey8924e872015-11-30 12:52:10 -0700858 private void initIfReadyAndConnected() {
859 Slog.d(TAG, "Thinking about init, mSystemReady=" + mSystemReady
860 + ", mDaemonConnected=" + mDaemonConnected);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700861 if (mSystemReady && mDaemonConnected
Paul Lawrence20be5d62016-02-26 13:51:17 -0800862 && !StorageManager.isFileEncryptedNativeOnly()) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700863 // When booting a device without native support, make sure that our
864 // user directories are locked or unlocked based on the current
865 // emulation status.
Paul Lawrence20be5d62016-02-26 13:51:17 -0800866 final boolean initLocked = StorageManager.isFileEncryptedEmulatedOnly();
Paul Crowleyd94ab732016-02-15 06:44:51 +0000867 Slog.d(TAG, "Setting up emulation state, initlocked=" + initLocked);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700868 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Jeff Sharkey8924e872015-11-30 12:52:10 -0700869 for (UserInfo user : users) {
870 try {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700871 if (initLocked) {
872 mCryptConnector.execute("cryptfs", "lock_user_key", user.id);
873 } else {
874 mCryptConnector.execute("cryptfs", "unlock_user_key", user.id,
Paul Crowleyd94ab732016-02-15 06:44:51 +0000875 user.serialNumber, "!", "!");
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700876 }
Jeff Sharkey8924e872015-11-30 12:52:10 -0700877 } catch (NativeDaemonConnectorException e) {
878 Slog.w(TAG, "Failed to init vold", e);
879 }
880 }
881 }
882 }
883
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800884 private void resetIfReadyAndConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700885 Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
886 + ", mDaemonConnected=" + mDaemonConnected);
887 if (mSystemReady && mDaemonConnected) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800888 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700889 killMediaProvider(users);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700890
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700891 final int[] systemUnlockedUsers;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800892 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700893 systemUnlockedUsers = mSystemUnlockedUsers;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700894
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800895 mDisks.clear();
896 mVolumes.clear();
897
898 addInternalVolumeLocked();
899 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700900
Jeff Sharkey48877892015-03-18 11:27:19 -0700901 try {
902 mConnector.execute("volume", "reset");
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700903
904 // Tell vold about all existing and started users
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700905 for (UserInfo user : users) {
906 mConnector.execute("volume", "user_added", user.id, user.serialNumber);
907 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700908 for (int userId : systemUnlockedUsers) {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700909 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey50a05452015-04-29 11:24:52 -0700910 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700911 } catch (NativeDaemonConnectorException e) {
912 Slog.w(TAG, "Failed to reset vold", e);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700913 }
914 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700915 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700916
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700917 private void onUnlockUser(int userId) {
918 Slog.d(TAG, "onUnlockUser " + userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700919
920 // We purposefully block here to make sure that user-specific
921 // staging area is ready so it's ready for zygote-forked apps to
922 // bind mount against.
923 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700924 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700925 } catch (NativeDaemonConnectorException ignored) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700926 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700927
928 // Record user as started so newly mounted volumes kick off events
929 // correctly, then synthesize events for any already-mounted volumes.
yuanhuihuiefd1f122016-07-13 21:21:03 +0800930 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700931 for (int i = 0; i < mVolumes.size(); i++) {
932 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey46349872015-07-28 10:49:47 -0700933 if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700934 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey48877892015-03-18 11:27:19 -0700935 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700936
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700937 final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
938 mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700939 }
940 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700941 mSystemUnlockedUsers = ArrayUtils.appendInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700942 }
943 }
944
945 private void onCleanupUser(int userId) {
946 Slog.d(TAG, "onCleanupUser " + userId);
947
948 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700949 mConnector.execute("volume", "user_stopped", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700950 } catch (NativeDaemonConnectorException ignored) {
951 }
952
yuanhuihuiefd1f122016-07-13 21:21:03 +0800953 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700954 mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700955 }
956 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700957
Christopher Tated417d622013-08-19 16:14:25 -0700958 void runIdleMaintenance(Runnable callback) {
959 mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
960 }
961
Christopher Tate7265abe2014-11-21 13:54:45 -0800962 // Binder entry point for kicking off an immediate fstrim
963 @Override
964 public void runMaintenance() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700965 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Christopher Tate7265abe2014-11-21 13:54:45 -0800966 runIdleMaintenance(null);
967 }
968
969 @Override
970 public long lastMaintenance() {
971 return mLastMaintenance;
972 }
973
San Mehat4270e1e2010-01-29 05:32:19 -0800974 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800975 * Callback from NativeDaemonConnector
976 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700977 @Override
San Mehat4270e1e2010-01-29 05:32:19 -0800978 public void onDaemonConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700979 mDaemonConnected = true;
980 mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();
981 }
982
983 private void handleDaemonConnected() {
Jeff Sharkey8924e872015-11-30 12:52:10 -0700984 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800985 resetIfReadyAndConnected();
Jeff Sharkey48877892015-03-18 11:27:19 -0700986
San Mehat4270e1e2010-01-29 05:32:19 -0800987 /*
Jeff Sharkey48877892015-03-18 11:27:19 -0700988 * Now that we've done our initialization, release
989 * the hounds!
San Mehat4270e1e2010-01-29 05:32:19 -0800990 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700991 mConnectedSignal.countDown();
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700992 if (mConnectedSignal.getCount() != 0) {
993 // More daemons need to connect
994 return;
995 }
Mike Lockwood7fa24aa2011-03-23 14:52:34 -0400996
Jeff Sharkey48877892015-03-18 11:27:19 -0700997 // On an encrypted device we can't see system properties yet, so pull
998 // the system locale out of the mount service.
999 if ("".equals(SystemProperties.get("vold.encrypt_progress"))) {
1000 copyLocaleFromMountService();
1001 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001002
Jeff Sharkey48877892015-03-18 11:27:19 -07001003 // Let package manager load internal ASECs.
1004 mPms.scanAvailableAsecs();
Mike Lockwood7fa24aa2011-03-23 14:52:34 -04001005
Jeff Sharkey48877892015-03-18 11:27:19 -07001006 // Notify people waiting for ASECs to be scanned that it's done.
1007 mAsecsScanned.countDown();
San Mehat4270e1e2010-01-29 05:32:19 -08001008 }
1009
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001010 private void copyLocaleFromMountService() {
1011 String systemLocale;
1012 try {
1013 systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
1014 } catch (RemoteException e) {
1015 return;
1016 }
1017 if (TextUtils.isEmpty(systemLocale)) {
1018 return;
1019 }
1020
1021 Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
1022 Locale locale = Locale.forLanguageTag(systemLocale);
1023 Configuration config = new Configuration();
1024 config.setLocale(locale);
1025 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001026 ActivityManager.getService().updatePersistentConfiguration(config);
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001027 } catch (RemoteException e) {
1028 Slog.e(TAG, "Error setting system locale from mount service", e);
1029 }
Elliott Hughes9c33f282014-10-13 12:39:56 -07001030
1031 // Temporary workaround for http://b/17945169.
1032 Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
Narayan Kamathd30dbb82015-01-15 14:48:15 +00001033 SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001034 }
1035
San Mehat4270e1e2010-01-29 05:32:19 -08001036 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001037 * Callback from NativeDaemonConnector
1038 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001039 @Override
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001040 public boolean onCheckHoldWakeLock(int code) {
1041 return false;
1042 }
1043
1044 /**
1045 * Callback from NativeDaemonConnector
1046 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001047 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001048 public boolean onEvent(int code, String raw, String[] cooked) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001049 synchronized (mLock) {
1050 return onEventLocked(code, raw, cooked);
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -08001051 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001052 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001053
Jeff Sharkey48877892015-03-18 11:27:19 -07001054 private boolean onEventLocked(int code, String raw, String[] cooked) {
1055 switch (code) {
1056 case VoldResponseCode.DISK_CREATED: {
1057 if (cooked.length != 3) break;
1058 final String id = cooked[1];
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001059 int flags = Integer.parseInt(cooked[2]);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001060 if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false)
1061 || mForceAdoptable) {
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001062 flags |= DiskInfo.FLAG_ADOPTABLE;
1063 }
Jeff Sharkey6ed74182016-08-23 13:53:53 -06001064 // Adoptable storage isn't currently supported on FBE devices
1065 if (StorageManager.isFileEncryptedNativeOnly()) {
1066 flags &= ~DiskInfo.FLAG_ADOPTABLE;
1067 }
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001068 mDisks.put(id, new DiskInfo(id, flags));
Jeff Sharkey48877892015-03-18 11:27:19 -07001069 break;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001070 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001071 case VoldResponseCode.DISK_SIZE_CHANGED: {
1072 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001073 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001074 if (disk != null) {
1075 disk.size = Long.parseLong(cooked[2]);
San Mehat4270e1e2010-01-29 05:32:19 -08001076 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001077 break;
1078 }
1079 case VoldResponseCode.DISK_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001080 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001081 if (disk != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001082 final StringBuilder builder = new StringBuilder();
1083 for (int i = 2; i < cooked.length; i++) {
1084 builder.append(cooked[i]).append(' ');
1085 }
1086 disk.label = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001087 }
1088 break;
1089 }
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001090 case VoldResponseCode.DISK_SCANNED: {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001091 if (cooked.length != 2) break;
1092 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001093 if (disk != null) {
1094 onDiskScannedLocked(disk);
1095 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -07001096 break;
1097 }
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001098 case VoldResponseCode.DISK_SYS_PATH_CHANGED: {
1099 if (cooked.length != 3) break;
1100 final DiskInfo disk = mDisks.get(cooked[1]);
1101 if (disk != null) {
1102 disk.sysPath = cooked[2];
1103 }
1104 break;
1105 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001106 case VoldResponseCode.DISK_DESTROYED: {
1107 if (cooked.length != 2) break;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07001108 final DiskInfo disk = mDisks.remove(cooked[1]);
1109 if (disk != null) {
1110 mCallbacks.notifyDiskDestroyed(disk);
1111 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001112 break;
1113 }
San Mehat4270e1e2010-01-29 05:32:19 -08001114
Jeff Sharkey48877892015-03-18 11:27:19 -07001115 case VoldResponseCode.VOLUME_CREATED: {
Jeff Sharkey48877892015-03-18 11:27:19 -07001116 final String id = cooked[1];
1117 final int type = Integer.parseInt(cooked[2]);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001118 final String diskId = TextUtils.nullIfEmpty(cooked[3]);
1119 final String partGuid = TextUtils.nullIfEmpty(cooked[4]);
1120
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001121 final DiskInfo disk = mDisks.get(diskId);
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07001122 final VolumeInfo vol = new VolumeInfo(id, type, disk, partGuid);
Jeff Sharkey48877892015-03-18 11:27:19 -07001123 mVolumes.put(id, vol);
1124 onVolumeCreatedLocked(vol);
1125 break;
1126 }
1127 case VoldResponseCode.VOLUME_STATE_CHANGED: {
1128 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001129 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001130 if (vol != null) {
1131 final int oldState = vol.state;
1132 final int newState = Integer.parseInt(cooked[2]);
1133 vol.state = newState;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001134 onVolumeStateChangedLocked(vol, oldState, newState);
Jeff Sharkey48877892015-03-18 11:27:19 -07001135 }
1136 break;
1137 }
1138 case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: {
1139 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001140 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001141 if (vol != null) {
1142 vol.fsType = cooked[2];
1143 }
1144 break;
1145 }
1146 case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
1147 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001148 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001149 if (vol != null) {
1150 vol.fsUuid = cooked[2];
1151 }
1152 break;
1153 }
1154 case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001155 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001156 if (vol != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001157 final StringBuilder builder = new StringBuilder();
1158 for (int i = 2; i < cooked.length; i++) {
1159 builder.append(cooked[i]).append(' ');
1160 }
1161 vol.fsLabel = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001162 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001163 // TODO: notify listeners that label changed
Jeff Sharkey48877892015-03-18 11:27:19 -07001164 break;
1165 }
1166 case VoldResponseCode.VOLUME_PATH_CHANGED: {
1167 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001168 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001169 if (vol != null) {
1170 vol.path = cooked[2];
1171 }
1172 break;
1173 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001174 case VoldResponseCode.VOLUME_INTERNAL_PATH_CHANGED: {
1175 if (cooked.length != 3) break;
1176 final VolumeInfo vol = mVolumes.get(cooked[1]);
1177 if (vol != null) {
1178 vol.internalPath = cooked[2];
1179 }
1180 break;
1181 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001182 case VoldResponseCode.VOLUME_DESTROYED: {
1183 if (cooked.length != 2) break;
1184 mVolumes.remove(cooked[1]);
1185 break;
1186 }
San Mehat4270e1e2010-01-29 05:32:19 -08001187
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001188 case VoldResponseCode.MOVE_STATUS: {
1189 final int status = Integer.parseInt(cooked[1]);
1190 onMoveStatusLocked(status);
1191 break;
1192 }
Jeff Sharkey9756d752015-05-14 21:07:42 -07001193 case VoldResponseCode.BENCHMARK_RESULT: {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001194 if (cooked.length != 7) break;
1195 final String path = cooked[1];
1196 final String ident = cooked[2];
1197 final long create = Long.parseLong(cooked[3]);
1198 final long drop = Long.parseLong(cooked[4]);
1199 final long run = Long.parseLong(cooked[5]);
1200 final long destroy = Long.parseLong(cooked[6]);
1201
Jeff Sharkey9756d752015-05-14 21:07:42 -07001202 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001203 dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
1204 + " " + ident + " " + create + " " + run + " " + destroy);
1205
1206 final VolumeRecord rec = findRecordForPath(path);
1207 if (rec != null) {
1208 rec.lastBenchMillis = System.currentTimeMillis();
1209 writeSettingsLocked();
1210 }
1211
1212 break;
1213 }
1214 case VoldResponseCode.TRIM_RESULT: {
1215 if (cooked.length != 4) break;
1216 final String path = cooked[1];
1217 final long bytes = Long.parseLong(cooked[2]);
1218 final long time = Long.parseLong(cooked[3]);
1219
1220 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
1221 dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path)
1222 + " " + bytes + " " + time);
1223
1224 final VolumeRecord rec = findRecordForPath(path);
1225 if (rec != null) {
1226 rec.lastTrimMillis = System.currentTimeMillis();
1227 writeSettingsLocked();
1228 }
1229
Jeff Sharkey9756d752015-05-14 21:07:42 -07001230 break;
1231 }
1232
Jeff Sharkey48877892015-03-18 11:27:19 -07001233 default: {
1234 Slog.d(TAG, "Unhandled vold event " + code);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001235 }
San Mehat4270e1e2010-01-29 05:32:19 -08001236 }
1237
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001238 return true;
San Mehat4270e1e2010-01-29 05:32:19 -08001239 }
1240
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001241 private void onDiskScannedLocked(DiskInfo disk) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001242 int volumeCount = 0;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001243 for (int i = 0; i < mVolumes.size(); i++) {
1244 final VolumeInfo vol = mVolumes.valueAt(i);
1245 if (Objects.equals(disk.id, vol.getDiskId())) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001246 volumeCount++;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001247 }
1248 }
1249
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001250 final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
Jeff Sharkey7732e1e2016-03-30 17:14:23 -06001251 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1252 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001253 intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
1254 intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001255 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001256
1257 final CountDownLatch latch = mDiskScanLatches.remove(disk.id);
1258 if (latch != null) {
1259 latch.countDown();
1260 }
1261
Jeff Sharkeyf5a6bd72015-05-19 14:42:38 -07001262 disk.volumeCount = volumeCount;
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001263 mCallbacks.notifyDiskScanned(disk, volumeCount);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001264 }
1265
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001266 private void onVolumeCreatedLocked(VolumeInfo vol) {
Jeff Sharkey6855c482016-03-31 14:34:38 -06001267 if (mPms.isOnlyCoreApps()) {
1268 Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId());
1269 return;
1270 }
1271
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001272 if (vol.type == VolumeInfo.TYPE_EMULATED) {
1273 final StorageManager storage = mContext.getSystemService(StorageManager.class);
1274 final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
1275
1276 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
1277 && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
1278 Slog.v(TAG, "Found primary storage at " + vol);
1279 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1280 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1281 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1282
1283 } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
1284 Slog.v(TAG, "Found primary storage at " + vol);
1285 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1286 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1287 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1288 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001289
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001290 } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001291 // TODO: only look at first public partition
1292 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1293 && vol.disk.isDefaultPrimary()) {
1294 Slog.v(TAG, "Found primary storage at " + vol);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001295 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1296 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
San Mehat4270e1e2010-01-29 05:32:19 -08001297 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001298
1299 // Adoptable public disks are visible to apps, since they meet
1300 // public API requirement of being in a stable location.
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001301 if (vol.disk.isAdoptable()) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001302 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1303 }
1304
Jeff Sharkeyab15c392016-05-05 11:45:01 -06001305 vol.mountUserId = mCurrentUserId;
Jeff Sharkey48877892015-03-18 11:27:19 -07001306 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001307
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001308 } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1309 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1310
San Mehat4270e1e2010-01-29 05:32:19 -08001311 } else {
Jeff Sharkey48877892015-03-18 11:27:19 -07001312 Slog.d(TAG, "Skipping automatic mounting of " + vol);
San Mehat4270e1e2010-01-29 05:32:19 -08001313 }
1314 }
1315
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001316 private boolean isBroadcastWorthy(VolumeInfo vol) {
1317 switch (vol.getType()) {
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001318 case VolumeInfo.TYPE_PRIVATE:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001319 case VolumeInfo.TYPE_PUBLIC:
1320 case VolumeInfo.TYPE_EMULATED:
1321 break;
1322 default:
1323 return false;
1324 }
1325
1326 switch (vol.getState()) {
1327 case VolumeInfo.STATE_MOUNTED:
1328 case VolumeInfo.STATE_MOUNTED_READ_ONLY:
1329 case VolumeInfo.STATE_EJECTING:
1330 case VolumeInfo.STATE_UNMOUNTED:
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001331 case VolumeInfo.STATE_UNMOUNTABLE:
Tony Mantlerf0d71052015-06-24 11:45:25 -07001332 case VolumeInfo.STATE_BAD_REMOVAL:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001333 break;
1334 default:
1335 return false;
1336 }
1337
1338 return true;
1339 }
1340
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001341 private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001342 // Remember that we saw this volume so we're ready to accept user
1343 // metadata, or so we can annoy them when a private volume is ejected
1344 if (vol.isMountedReadable() && !TextUtils.isEmpty(vol.fsUuid)) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001345 VolumeRecord rec = mRecords.get(vol.fsUuid);
1346 if (rec == null) {
1347 rec = new VolumeRecord(vol.type, vol.fsUuid);
1348 rec.partGuid = vol.partGuid;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001349 rec.createdMillis = System.currentTimeMillis();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001350 if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1351 rec.nickname = vol.disk.getDescription();
1352 }
1353 mRecords.put(rec.fsUuid, rec);
1354 writeSettingsLocked();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001355 } else {
1356 // Handle upgrade case where we didn't store partition GUID
1357 if (TextUtils.isEmpty(rec.partGuid)) {
1358 rec.partGuid = vol.partGuid;
1359 writeSettingsLocked();
1360 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001361 }
1362 }
1363
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001364 mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
1365
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001366 // Do not broadcast before boot has completed to avoid launching the
1367 // processes that receive the intent unnecessarily.
1368 if (mBootCompleted && isBroadcastWorthy(vol)) {
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001369 final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001370 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
1371 intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
Tony Mantlerf0d71052015-06-24 11:45:25 -07001372 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
Jeff Sharkey7732e1e2016-03-30 17:14:23 -06001373 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1374 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001375 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001376 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001377
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001378 final String oldStateEnv = VolumeInfo.getEnvironmentForState(oldState);
1379 final String newStateEnv = VolumeInfo.getEnvironmentForState(newState);
Emily Bernier92aa5a22014-07-07 10:11:48 -04001380
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001381 if (!Objects.equals(oldStateEnv, newStateEnv)) {
1382 // Kick state changed event towards all started users. Any users
1383 // started after this point will trigger additional
1384 // user-specific broadcasts.
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001385 for (int userId : mSystemUnlockedUsers) {
Jeff Sharkey46349872015-07-28 10:49:47 -07001386 if (vol.isVisibleForRead(userId)) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001387 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001388 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey48877892015-03-18 11:27:19 -07001389
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001390 mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
1391 newStateEnv);
San Mehat4270e1e2010-01-29 05:32:19 -08001392 }
1393 }
1394 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001395
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001396 if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.state == VolumeInfo.STATE_EJECTING) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001397 // TODO: this should eventually be handled by new ObbVolume state changes
1398 /*
1399 * Some OBBs might have been unmounted when this volume was
1400 * unmounted, so send a message to the handler to let it know to
1401 * remove those from the list of mounted OBBS.
1402 */
1403 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
1404 OBB_FLUSH_MOUNT_STATE, vol.path));
1405 }
San Mehat4270e1e2010-01-29 05:32:19 -08001406 }
1407
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001408 private void onMoveStatusLocked(int status) {
1409 if (mMoveCallback == null) {
1410 Slog.w(TAG, "Odd, status but no move requested");
1411 return;
1412 }
1413
1414 // TODO: estimate remaining time
1415 try {
Jeff Sharkey50a05452015-04-29 11:24:52 -07001416 mMoveCallback.onStatusChanged(-1, status, -1);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001417 } catch (RemoteException ignored) {
1418 }
1419
1420 // We've finished copying and we're about to clean up old data, so
1421 // remember that move was successful if we get rebooted
1422 if (status == MOVE_STATUS_COPY_FINISHED) {
1423 Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
1424
1425 mPrimaryStorageUuid = mMoveTargetUuid;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001426 writeSettingsLocked();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001427 }
1428
1429 if (PackageManager.isMoveStatusFinished(status)) {
1430 Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status);
1431
1432 mMoveCallback = null;
1433 mMoveTargetUuid = null;
1434 }
1435 }
1436
Jeff Sharkey48877892015-03-18 11:27:19 -07001437 private void enforcePermission(String perm) {
1438 mContext.enforceCallingOrSelfPermission(perm, perm);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001439 }
1440
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001441 /**
1442 * Decide if volume is mountable per device policies.
1443 */
1444 private boolean isMountDisallowed(VolumeInfo vol) {
Philip P. Moltmannec3cbb22016-09-14 13:24:52 -07001445 UserManager userManager = mContext.getSystemService(UserManager.class);
1446
1447 boolean isUsbRestricted = false;
1448 if (vol.disk != null && vol.disk.isUsb()) {
1449 isUsbRestricted = userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER,
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001450 Binder.getCallingUserHandle());
Emily Bernier92aa5a22014-07-07 10:11:48 -04001451 }
Philip P. Moltmannec3cbb22016-09-14 13:24:52 -07001452
1453 boolean isTypeRestricted = false;
1454 if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
1455 isTypeRestricted = userManager
1456 .hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
1457 Binder.getCallingUserHandle());
1458 }
1459
1460 return isUsbRestricted || isTypeRestricted;
Emily Bernier92aa5a22014-07-07 10:11:48 -04001461 }
1462
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001463 private void enforceAdminUser() {
1464 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1465 final int callingUserId = UserHandle.getCallingUserId();
1466 boolean isAdmin;
1467 long token = Binder.clearCallingIdentity();
1468 try {
1469 isAdmin = um.getUserInfo(callingUserId).isAdmin();
1470 } finally {
1471 Binder.restoreCallingIdentity(token);
1472 }
1473 if (!isAdmin) {
1474 throw new SecurityException("Only admin users can adopt sd cards");
1475 }
1476 }
1477
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001478 /**
Sudheer Shanka2250d562016-11-07 15:41:02 -08001479 * Constructs a new StorageManagerService instance
San Mehat207e5382010-02-04 20:46:54 -08001480 *
1481 * @param context Binder context for this service
1482 */
Sudheer Shanka2250d562016-11-07 15:41:02 -08001483 public StorageManagerService(Context context) {
Christopher Tated417d622013-08-19 16:14:25 -07001484 sSelf = this;
1485
San Mehat207e5382010-02-04 20:46:54 -08001486 mContext = context;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001487 mCallbacks = new Callbacks(FgThread.get().getLooper());
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001488 mLockPatternUtils = new LockPatternUtils(mContext);
San Mehat207e5382010-02-04 20:46:54 -08001489
San Mehat207e5382010-02-04 20:46:54 -08001490 // XXX: This will go away soon in favor of IMountServiceObserver
1491 mPms = (PackageManagerService) ServiceManager.getService("package");
1492
Dianne Hackbornefa92b22013-05-03 14:11:43 -07001493 HandlerThread hthread = new HandlerThread(TAG);
1494 hthread.start();
Sudheer Shanka2250d562016-11-07 15:41:02 -08001495 mHandler = new StorageManagerServiceHandler(hthread.getLooper());
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001496
Sudheer Shanka2250d562016-11-07 15:41:02 -08001497 // Add OBB Action Handler to StorageManagerService thread.
Dianne Hackborn8d044e82013-04-30 17:24:15 -07001498 mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
Kenny Roota02b8b02010-08-05 16:14:17 -07001499
Christopher Tate7265abe2014-11-21 13:54:45 -08001500 // Initialize the last-fstrim tracking if necessary
1501 File dataDir = Environment.getDataDirectory();
1502 File systemDir = new File(dataDir, "system");
1503 mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
1504 if (!mLastMaintenanceFile.exists()) {
1505 // Not setting mLastMaintenance here means that we will force an
1506 // fstrim during reboot following the OTA that installs this code.
1507 try {
1508 (new FileOutputStream(mLastMaintenanceFile)).close();
1509 } catch (IOException e) {
1510 Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
1511 }
1512 } else {
1513 mLastMaintenance = mLastMaintenanceFile.lastModified();
1514 }
1515
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001516 mSettingsFile = new AtomicFile(
Jeff Sharkey8212ae02016-02-10 14:46:43 -07001517 new File(Environment.getDataSystemDirectory(), "storage.xml"));
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001518
1519 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001520 readSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001521 }
1522
Sudheer Shanka2250d562016-11-07 15:41:02 -08001523 LocalServices.addService(StorageManagerInternal.class, mStorageManagerInternal);
Svet Ganov6ee871e2015-07-10 14:29:33 -07001524
Marco Nelissenc34ebce2010-02-18 13:39:41 -08001525 /*
Kenny Root305bcbf2010-09-03 07:56:38 -07001526 * Create the connection to vold with a maximum queue of twice the
1527 * amount of containers we'd ever expect to have. This keeps an
1528 * "asec list" from blocking a thread repeatedly.
1529 */
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001530
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001531 mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
1532 null);
Jeff Sharkey48877892015-03-18 11:27:19 -07001533 mConnector.setDebug(true);
Jeff Sharkey8948c012015-11-03 12:33:54 -08001534 mConnector.setWarnIfHeld(mLock);
Jeff Sharkeycd575992016-03-29 14:12:49 -06001535 mConnectorThread = new Thread(mConnector, VOLD_TAG);
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07001536
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001537 // Reuse parameters from first connector since they are tested and safe
1538 mCryptConnector = new NativeDaemonConnector(this, "cryptd",
1539 MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
1540 mCryptConnector.setDebug(true);
Jeff Sharkeycd575992016-03-29 14:12:49 -06001541 mCryptConnectorThread = new Thread(mCryptConnector, CRYPTD_TAG);
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001542
Jeff Sharkeybcd262d2015-06-10 09:41:17 -07001543 final IntentFilter userFilter = new IntentFilter();
1544 userFilter.addAction(Intent.ACTION_USER_ADDED);
1545 userFilter.addAction(Intent.ACTION_USER_REMOVED);
1546 mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
1547
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001548 synchronized (mLock) {
1549 addInternalVolumeLocked();
1550 }
Amith Yamasania7892482015-08-07 11:09:05 -07001551
Kenny Root07714d42011-08-17 17:49:28 -07001552 // Add ourself to the Watchdog monitors if enabled.
1553 if (WATCHDOG_ENABLE) {
1554 Watchdog.getInstance().addMonitor(this);
1555 }
San Mehat207e5382010-02-04 20:46:54 -08001556 }
1557
Jeff Sharkeycd575992016-03-29 14:12:49 -06001558 private void start() {
1559 mConnectorThread.start();
1560 mCryptConnectorThread.start();
1561 }
1562
Jeff Sharkey56e62932015-03-21 20:41:00 -07001563 private void systemReady() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001564 mSystemReady = true;
1565 mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
1566 }
1567
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001568 private void bootCompleted() {
1569 mBootCompleted = true;
1570 }
1571
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001572 private String getDefaultPrimaryStorageUuid() {
1573 if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) {
1574 return StorageManager.UUID_PRIMARY_PHYSICAL;
1575 } else {
1576 return StorageManager.UUID_PRIVATE_INTERNAL;
1577 }
1578 }
1579
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001580 private void readSettingsLocked() {
1581 mRecords.clear();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001582 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001583 mForceAdoptable = false;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001584
1585 FileInputStream fis = null;
1586 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001587 fis = mSettingsFile.openRead();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001588 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001589 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001590
1591 int type;
1592 while ((type = in.next()) != END_DOCUMENT) {
1593 if (type == START_TAG) {
1594 final String tag = in.getName();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001595 if (TAG_VOLUMES.equals(tag)) {
1596 final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001597 final boolean primaryPhysical = SystemProperties.getBoolean(
1598 StorageManager.PROP_PRIMARY_PHYSICAL, false);
1599 final boolean validAttr = (version >= VERSION_FIX_PRIMARY)
1600 || (version >= VERSION_ADD_PRIMARY && !primaryPhysical);
1601 if (validAttr) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001602 mPrimaryStorageUuid = readStringAttribute(in,
1603 ATTR_PRIMARY_STORAGE_UUID);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001604 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001605 mForceAdoptable = readBooleanAttribute(in, ATTR_FORCE_ADOPTABLE, false);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001606
1607 } else if (TAG_VOLUME.equals(tag)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001608 final VolumeRecord rec = readVolumeRecord(in);
1609 mRecords.put(rec.fsUuid, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001610 }
1611 }
1612 }
1613 } catch (FileNotFoundException e) {
1614 // Missing metadata is okay, probably first boot
1615 } catch (IOException e) {
1616 Slog.wtf(TAG, "Failed reading metadata", e);
1617 } catch (XmlPullParserException e) {
1618 Slog.wtf(TAG, "Failed reading metadata", e);
1619 } finally {
1620 IoUtils.closeQuietly(fis);
1621 }
1622 }
1623
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001624 private void writeSettingsLocked() {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001625 FileOutputStream fos = null;
1626 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001627 fos = mSettingsFile.startWrite();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001628
1629 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001630 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001631 out.startDocument(null, true);
1632 out.startTag(null, TAG_VOLUMES);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001633 writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001634 writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001635 writeBooleanAttribute(out, ATTR_FORCE_ADOPTABLE, mForceAdoptable);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001636 final int size = mRecords.size();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001637 for (int i = 0; i < size; i++) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001638 final VolumeRecord rec = mRecords.valueAt(i);
1639 writeVolumeRecord(out, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001640 }
1641 out.endTag(null, TAG_VOLUMES);
1642 out.endDocument();
1643
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001644 mSettingsFile.finishWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001645 } catch (IOException e) {
1646 if (fos != null) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001647 mSettingsFile.failWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001648 }
1649 }
1650 }
1651
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001652 public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
1653 final int type = readIntAttribute(in, ATTR_TYPE);
1654 final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
1655 final VolumeRecord meta = new VolumeRecord(type, fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001656 meta.partGuid = readStringAttribute(in, ATTR_PART_GUID);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001657 meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
1658 meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001659 meta.createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
1660 meta.lastTrimMillis = readLongAttribute(in, ATTR_LAST_TRIM_MILLIS);
1661 meta.lastBenchMillis = readLongAttribute(in, ATTR_LAST_BENCH_MILLIS);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001662 return meta;
1663 }
1664
1665 public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
1666 out.startTag(null, TAG_VOLUME);
1667 writeIntAttribute(out, ATTR_TYPE, rec.type);
1668 writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001669 writeStringAttribute(out, ATTR_PART_GUID, rec.partGuid);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001670 writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
1671 writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001672 writeLongAttribute(out, ATTR_CREATED_MILLIS, rec.createdMillis);
1673 writeLongAttribute(out, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
1674 writeLongAttribute(out, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001675 out.endTag(null, TAG_VOLUME);
1676 }
1677
San Mehat207e5382010-02-04 20:46:54 -08001678 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001679 * Exposed API calls below here
1680 */
1681
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001682 @Override
Sudheer Shanka2250d562016-11-07 15:41:02 -08001683 public void registerListener(IStorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001684 mCallbacks.register(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001685 }
1686
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001687 @Override
Sudheer Shanka2250d562016-11-07 15:41:02 -08001688 public void unregisterListener(IStorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001689 mCallbacks.unregister(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001690 }
1691
Jeff Sharkey48877892015-03-18 11:27:19 -07001692 @Override
Sudheer Shanka2250d562016-11-07 15:41:02 -08001693 public void shutdown(final IStorageShutdownObserver observer) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001694 enforcePermission(android.Manifest.permission.SHUTDOWN);
San Mehat4270e1e2010-01-29 05:32:19 -08001695
San Mehata5078592010-03-25 09:36:54 -07001696 Slog.i(TAG, "Shutting down");
Jeff Sharkey48877892015-03-18 11:27:19 -07001697 mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001698 }
1699
Jeff Sharkey48877892015-03-18 11:27:19 -07001700 @Override
San Mehatb1043402010-02-05 08:26:50 -08001701 public boolean isUsbMassStorageConnected() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001702 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001703 }
1704
Jeff Sharkey48877892015-03-18 11:27:19 -07001705 @Override
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -08001706 public void setUsbMassStorageEnabled(boolean enable) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001707 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001708 }
1709
Jeff Sharkey48877892015-03-18 11:27:19 -07001710 @Override
San Mehatb1043402010-02-05 08:26:50 -08001711 public boolean isUsbMassStorageEnabled() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001712 throw new UnsupportedOperationException();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 }
Jason parks9ed98bc2011-01-17 09:58:35 -06001714
Jeff Sharkey48877892015-03-18 11:27:19 -07001715 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001716 public String getVolumeState(String mountPoint) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001717 throw new UnsupportedOperationException();
San Mehat7fd0fee2009-12-17 07:12:23 -08001718 }
1719
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001720 @Override
Kenny Roote1ff2142010-10-12 11:20:01 -07001721 public boolean isExternalStorageEmulated() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001722 throw new UnsupportedOperationException();
Kenny Roote1ff2142010-10-12 11:20:01 -07001723 }
1724
Jeff Sharkey48877892015-03-18 11:27:19 -07001725 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001726 public int mountVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001727 mount(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001728 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 }
1730
Jeff Sharkey48877892015-03-18 11:27:19 -07001731 @Override
Ben Komalo13c71972011-09-07 16:35:56 -07001732 public void unmountVolume(String path, boolean force, boolean removeEncryption) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001733 unmount(findVolumeIdForPathOrThrow(path));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 }
1735
Jeff Sharkey48877892015-03-18 11:27:19 -07001736 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001737 public int formatVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001738 format(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001739 return 0;
1740 }
1741
1742 @Override
1743 public void mount(String volId) {
1744 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1745 waitForReady();
1746
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001747 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001748 if (isMountDisallowed(vol)) {
1749 throw new SecurityException("Mounting " + volId + " restricted by policy");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001750 }
1751 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001752 mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001753 } catch (NativeDaemonConnectorException e) {
1754 throw e.rethrowAsParcelableException();
1755 }
1756 }
1757
1758 @Override
1759 public void unmount(String volId) {
1760 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1761 waitForReady();
1762
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001763 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001764
1765 // TODO: expand PMS to know about multiple volumes
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001766 if (vol.isPrimaryPhysical()) {
1767 final long ident = Binder.clearCallingIdentity();
1768 try {
1769 synchronized (mUnmountLock) {
1770 mUnmountSignal = new CountDownLatch(1);
1771 mPms.updateExternalMediaStatus(false, true);
1772 waitForLatch(mUnmountSignal, "mUnmountSignal");
1773 mUnmountSignal = null;
1774 }
1775 } finally {
1776 Binder.restoreCallingIdentity(ident);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001777 }
1778 }
1779
1780 try {
1781 mConnector.execute("volume", "unmount", vol.id);
1782 } catch (NativeDaemonConnectorException e) {
1783 throw e.rethrowAsParcelableException();
1784 }
1785 }
1786
1787 @Override
1788 public void format(String volId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001789 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -08001790 waitForReady();
San Mehat5b77dab2010-01-26 13:28:50 -08001791
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001792 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001793 try {
Jeff Sharkey4e83cc92015-05-27 14:38:39 -07001794 mConnector.execute("volume", "format", vol.id, "auto");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001795 } catch (NativeDaemonConnectorException e) {
1796 throw e.rethrowAsParcelableException();
Jeff Sharkey48877892015-03-18 11:27:19 -07001797 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001798 }
1799
1800 @Override
Jeff Sharkey9756d752015-05-14 21:07:42 -07001801 public long benchmark(String volId) {
1802 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1803 waitForReady();
1804
1805 try {
Jeff Sharkey14cbe522015-07-08 14:06:37 -07001806 // TODO: make benchmark async so we don't block other commands
1807 final NativeDaemonEvent res = mConnector.execute(3 * DateUtils.MINUTE_IN_MILLIS,
1808 "volume", "benchmark", volId);
Jeff Sharkey9756d752015-05-14 21:07:42 -07001809 return Long.parseLong(res.getMessage());
Todd Kennedy8101ee62015-06-23 13:35:28 -07001810 } catch (NativeDaemonTimeoutException e) {
1811 return Long.MAX_VALUE;
Jeff Sharkey9756d752015-05-14 21:07:42 -07001812 } catch (NativeDaemonConnectorException e) {
1813 throw e.rethrowAsParcelableException();
1814 }
1815 }
1816
1817 @Override
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001818 public void partitionPublic(String diskId) {
1819 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1820 waitForReady();
1821
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001822 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001823 try {
1824 mConnector.execute("volume", "partition", diskId, "public");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001825 waitForLatch(latch, "partitionPublic", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001826 } catch (NativeDaemonConnectorException e) {
1827 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001828 } catch (TimeoutException e) {
1829 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001830 }
1831 }
1832
1833 @Override
1834 public void partitionPrivate(String diskId) {
1835 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001836 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001837 waitForReady();
1838
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001839 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001840 try {
1841 mConnector.execute("volume", "partition", diskId, "private");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001842 waitForLatch(latch, "partitionPrivate", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001843 } catch (NativeDaemonConnectorException e) {
1844 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001845 } catch (TimeoutException e) {
1846 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001847 }
1848 }
1849
1850 @Override
1851 public void partitionMixed(String diskId, int ratio) {
1852 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001853 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001854 waitForReady();
1855
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001856 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001857 try {
1858 mConnector.execute("volume", "partition", diskId, "mixed", ratio);
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001859 waitForLatch(latch, "partitionMixed", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001860 } catch (NativeDaemonConnectorException e) {
1861 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001862 } catch (TimeoutException e) {
1863 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001864 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001865 }
1866
Jeff Sharkey48877892015-03-18 11:27:19 -07001867 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001868 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001869 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1870 waitForReady();
1871
Jeff Sharkey50a05452015-04-29 11:24:52 -07001872 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001873 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001874 final VolumeRecord rec = mRecords.get(fsUuid);
1875 rec.nickname = nickname;
Jeff Sharkey50a05452015-04-29 11:24:52 -07001876 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001877 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001878 }
1879 }
1880
1881 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001882 public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001883 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1884 waitForReady();
1885
Jeff Sharkey50a05452015-04-29 11:24:52 -07001886 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001887 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001888 final VolumeRecord rec = mRecords.get(fsUuid);
1889 rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001890 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001891 writeSettingsLocked();
1892 }
1893 }
1894
1895 @Override
1896 public void forgetVolume(String fsUuid) {
1897 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1898 waitForReady();
1899
Jeff Sharkey50a05452015-04-29 11:24:52 -07001900 Preconditions.checkNotNull(fsUuid);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001901
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001902 synchronized (mLock) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001903 final VolumeRecord rec = mRecords.remove(fsUuid);
1904 if (rec != null && !TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001905 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001906 }
1907 mCallbacks.notifyVolumeForgotten(fsUuid);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001908
1909 // If this had been primary storage, revert back to internal and
1910 // reset vold so we bind into new volume into place.
1911 if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001912 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001913 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001914 }
1915
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001916 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001917 }
1918 }
1919
Jeff Sharkey7d2af542015-05-12 15:27:15 -07001920 @Override
1921 public void forgetAllVolumes() {
1922 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1923 waitForReady();
1924
Jeff Sharkey50a05452015-04-29 11:24:52 -07001925 synchronized (mLock) {
1926 for (int i = 0; i < mRecords.size(); i++) {
1927 final String fsUuid = mRecords.keyAt(i);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001928 final VolumeRecord rec = mRecords.valueAt(i);
1929 if (!TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001930 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001931 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001932 mCallbacks.notifyVolumeForgotten(fsUuid);
1933 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001934 mRecords.clear();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001935
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001936 if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)) {
1937 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
1938 }
1939
1940 writeSettingsLocked();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001941 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001942 }
1943 }
1944
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001945 private void forgetPartition(String partGuid) {
1946 try {
1947 mConnector.execute("volume", "forget_partition", partGuid);
1948 } catch (NativeDaemonConnectorException e) {
1949 Slog.w(TAG, "Failed to forget key for " + partGuid + ": " + e);
1950 }
1951 }
1952
Jeff Sharkey31d0b702016-11-21 14:16:53 -07001953 @Override
1954 public void fstrim(int flags) {
1955 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1956 waitForReady();
1957
1958 String cmd;
1959 if ((flags & StorageManager.FSTRIM_FLAG_DEEP) != 0) {
1960 cmd = "dodtrim";
1961 } else {
1962 cmd = "dotrim";
1963 }
1964 if ((flags & StorageManager.FSTRIM_FLAG_BENCHMARK) != 0) {
1965 cmd += "bench";
1966 }
1967
1968 try {
1969 mConnector.execute("fstrim", cmd);
1970 } catch (NativeDaemonConnectorException e) {
1971 Slog.e(TAG, "Failed to run fstrim: " + e);
1972 }
1973 }
1974
Svet Ganov6ee871e2015-07-10 14:29:33 -07001975 private void remountUidExternalStorage(int uid, int mode) {
Jeff Sharkey9527b222015-06-24 15:24:48 -07001976 waitForReady();
1977
Svet Ganov6ee871e2015-07-10 14:29:33 -07001978 String modeName = "none";
1979 switch (mode) {
1980 case Zygote.MOUNT_EXTERNAL_DEFAULT: {
1981 modeName = "default";
1982 } break;
1983
1984 case Zygote.MOUNT_EXTERNAL_READ: {
1985 modeName = "read";
1986 } break;
1987
1988 case Zygote.MOUNT_EXTERNAL_WRITE: {
1989 modeName = "write";
1990 } break;
Jeff Sharkey9527b222015-06-24 15:24:48 -07001991 }
1992
1993 try {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001994 mConnector.execute("volume", "remount_uid", uid, modeName);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001995 } catch (NativeDaemonConnectorException e) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001996 Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e);
Jeff Sharkey9527b222015-06-24 15:24:48 -07001997 }
1998 }
1999
2000 @Override
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002001 public void setDebugFlags(int flags, int mask) {
2002 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2003 waitForReady();
2004
Jeff Sharkeyba512352015-11-12 20:17:45 -08002005 if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
Jeff Sharkey00455bf2016-11-04 14:45:24 -06002006 if (!EMULATE_FBE_SUPPORTED) {
2007 throw new IllegalStateException(
2008 "Emulation not supported on this device");
2009 }
Paul Lawrence20be5d62016-02-26 13:51:17 -08002010 if (StorageManager.isFileEncryptedNativeOnly()) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002011 throw new IllegalStateException(
Jeff Sharkey00455bf2016-11-04 14:45:24 -06002012 "Emulation not supported on device with native FBE");
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002013 }
Jeff Sharkey5a785162016-03-21 13:02:06 -06002014 if (mLockPatternUtils.isCredentialRequiredToDecrypt(false)) {
2015 throw new IllegalStateException(
2016 "Emulation requires disabling 'Secure start-up' in Settings > Security");
2017 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002018
Jeff Sharkey1176e512016-02-29 17:01:26 -07002019 final long token = Binder.clearCallingIdentity();
2020 try {
2021 final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
2022 SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002023
Jeff Sharkey1176e512016-02-29 17:01:26 -07002024 // Perform hard reboot to kick policy into place
2025 mContext.getSystemService(PowerManager.class).reboot(null);
2026 } finally {
2027 Binder.restoreCallingIdentity(token);
2028 }
Jeff Sharkeyba512352015-11-12 20:17:45 -08002029 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002030
Jeff Sharkeyba512352015-11-12 20:17:45 -08002031 if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
Jeff Sharkey6ed74182016-08-23 13:53:53 -06002032 if (StorageManager.isFileEncryptedNativeOnly()) {
2033 throw new IllegalStateException(
2034 "Adoptable storage not available on device with native FBE");
2035 }
2036
Jeff Sharkeyba512352015-11-12 20:17:45 -08002037 synchronized (mLock) {
2038 mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
2039
2040 writeSettingsLocked();
2041 mHandler.obtainMessage(H_RESET).sendToTarget();
2042 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002043 }
Jeff Sharkey33dd1562016-04-07 11:05:33 -06002044
2045 if ((mask & (StorageManager.DEBUG_SDCARDFS_FORCE_ON
2046 | StorageManager.DEBUG_SDCARDFS_FORCE_OFF)) != 0) {
2047 final String value;
2048 if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_ON) != 0) {
2049 value = "force_on";
2050 } else if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_OFF) != 0) {
2051 value = "force_off";
2052 } else {
2053 value = "";
2054 }
2055
2056 final long token = Binder.clearCallingIdentity();
2057 try {
2058 SystemProperties.set(StorageManager.PROP_SDCARDFS, value);
2059
2060 // Reset storage to kick new setting into place
2061 mHandler.obtainMessage(H_RESET).sendToTarget();
2062 } finally {
2063 Binder.restoreCallingIdentity(token);
2064 }
2065 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002066 }
2067
2068 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002069 public String getPrimaryStorageUuid() {
2070 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2071 waitForReady();
2072
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002073 synchronized (mLock) {
2074 return mPrimaryStorageUuid;
2075 }
2076 }
2077
2078 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002079 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
2080 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2081 waitForReady();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002082
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002083 final VolumeInfo from;
2084 final VolumeInfo to;
2085
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002086 synchronized (mLock) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002087 if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) {
2088 throw new IllegalArgumentException("Primary storage already at " + volumeUuid);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002089 }
2090
2091 if (mMoveCallback != null) {
2092 throw new IllegalStateException("Move already in progress");
2093 }
2094 mMoveCallback = callback;
2095 mMoveTargetUuid = volumeUuid;
2096
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002097 // When moving to/from primary physical volume, we probably just nuked
2098 // the current storage location, so we have nothing to move.
2099 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
2100 || Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
2101 Slog.d(TAG, "Skipping move to/from primary physical");
2102 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
2103 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08002104 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002105 return;
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002106
2107 } else {
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002108 from = findStorageForUuid(mPrimaryStorageUuid);
2109 to = findStorageForUuid(volumeUuid);
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07002110
2111 if (from == null) {
2112 Slog.w(TAG, "Failing move due to missing from volume " + mPrimaryStorageUuid);
2113 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2114 return;
2115 } else if (to == null) {
2116 Slog.w(TAG, "Failing move due to missing to volume " + volumeUuid);
2117 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2118 return;
2119 }
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002120 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002121 }
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002122
2123 try {
2124 mConnector.execute("volume", "move_storage", from.id, to.id);
2125 } catch (NativeDaemonConnectorException e) {
2126 throw e.rethrowAsParcelableException();
2127 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002128 }
2129
2130 @Override
Mike Lockwoodecedfdc2011-06-08 15:11:59 -07002131 public int[] getStorageUsers(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002132 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehatc1b4ce92010-02-16 17:13:03 -08002133 waitForReady();
2134 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002135 final String[] r = NativeDaemonEvent.filterMessageList(
2136 mConnector.executeForList("storage", "users", path),
2137 VoldResponseCode.StorageUsersListResult);
2138
San Mehatc1b4ce92010-02-16 17:13:03 -08002139 // FMT: <pid> <process name>
2140 int[] data = new int[r.length];
2141 for (int i = 0; i < r.length; i++) {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002142 String[] tok = r[i].split(" ");
San Mehatc1b4ce92010-02-16 17:13:03 -08002143 try {
2144 data[i] = Integer.parseInt(tok[0]);
2145 } catch (NumberFormatException nfe) {
San Mehata5078592010-03-25 09:36:54 -07002146 Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
San Mehatc1b4ce92010-02-16 17:13:03 -08002147 return new int[0];
2148 }
2149 }
2150 return data;
2151 } catch (NativeDaemonConnectorException e) {
San Mehata5078592010-03-25 09:36:54 -07002152 Slog.e(TAG, "Failed to retrieve storage users list", e);
San Mehatc1b4ce92010-02-16 17:13:03 -08002153 return new int[0];
2154 }
2155 }
2156
San Mehatb1043402010-02-05 08:26:50 -08002157 private void warnOnNotMounted() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002158 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002159 for (int i = 0; i < mVolumes.size(); i++) {
2160 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07002161 if (vol.isPrimary() && vol.isMountedWritable()) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002162 // Cool beans, we have a mounted primary volume
2163 return;
2164 }
Jeff Sharkey32ee8312012-09-30 13:21:31 -07002165 }
San Mehatb1043402010-02-05 08:26:50 -08002166 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002167
2168 Slog.w(TAG, "No primary storage mounted!");
San Mehatb1043402010-02-05 08:26:50 -08002169 }
2170
San Mehat4270e1e2010-01-29 05:32:19 -08002171 public String[] getSecureContainerList() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002172 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002173 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002174 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002175
San Mehat4270e1e2010-01-29 05:32:19 -08002176 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002177 return NativeDaemonEvent.filterMessageList(
2178 mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
San Mehat4270e1e2010-01-29 05:32:19 -08002179 } catch (NativeDaemonConnectorException e) {
2180 return new String[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002181 }
2182 }
San Mehat36972292010-01-06 11:06:32 -08002183
Kenny Root6dceb882012-04-12 14:23:49 -07002184 public int createSecureContainer(String id, int sizeMb, String fstype, String key,
2185 int ownerUid, boolean external) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002186 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehat207e5382010-02-04 20:46:54 -08002187 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002188 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002189
San Mehatb1043402010-02-05 08:26:50 -08002190 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002191 try {
Jeff Sharkey56cd6462013-06-07 15:09:15 -07002192 mConnector.execute("asec", "create", id, sizeMb, fstype, new SensitiveArg(key),
2193 ownerUid, external ? "1" : "0");
San Mehat4270e1e2010-01-29 05:32:19 -08002194 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002195 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002196 }
San Mehata181b212010-02-11 06:50:20 -08002197
2198 if (rc == StorageResultCode.OperationSucceeded) {
2199 synchronized (mAsecMountSet) {
2200 mAsecMountSet.add(id);
2201 }
2202 }
San Mehat4270e1e2010-01-29 05:32:19 -08002203 return rc;
San Mehat36972292010-01-06 11:06:32 -08002204 }
2205
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002206 @Override
2207 public int resizeSecureContainer(String id, int sizeMb, String key) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002208 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002209 waitForReady();
2210 warnOnNotMounted();
2211
2212 int rc = StorageResultCode.OperationSucceeded;
2213 try {
2214 mConnector.execute("asec", "resize", id, sizeMb, new SensitiveArg(key));
2215 } catch (NativeDaemonConnectorException e) {
2216 rc = StorageResultCode.OperationFailedInternalError;
2217 }
2218 return rc;
2219 }
2220
San Mehat4270e1e2010-01-29 05:32:19 -08002221 public int finalizeSecureContainer(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002222 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehatb1043402010-02-05 08:26:50 -08002223 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002224
San Mehatb1043402010-02-05 08:26:50 -08002225 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002226 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002227 mConnector.execute("asec", "finalize", id);
San Mehata181b212010-02-11 06:50:20 -08002228 /*
2229 * Finalization does a remount, so no need
2230 * to update mAsecMountSet
2231 */
San Mehat4270e1e2010-01-29 05:32:19 -08002232 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002233 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002234 }
San Mehat4270e1e2010-01-29 05:32:19 -08002235 return rc;
San Mehat36972292010-01-06 11:06:32 -08002236 }
2237
Kenny Root6dceb882012-04-12 14:23:49 -07002238 public int fixPermissionsSecureContainer(String id, int gid, String filename) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002239 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Kenny Root6dceb882012-04-12 14:23:49 -07002240 warnOnNotMounted();
2241
2242 int rc = StorageResultCode.OperationSucceeded;
2243 try {
2244 mConnector.execute("asec", "fixperms", id, gid, filename);
2245 /*
2246 * Fix permissions does a remount, so no need to update
2247 * mAsecMountSet
2248 */
2249 } catch (NativeDaemonConnectorException e) {
2250 rc = StorageResultCode.OperationFailedInternalError;
2251 }
2252 return rc;
2253 }
2254
San Mehatd9709982010-02-18 11:43:03 -08002255 public int destroySecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002256 enforcePermission(android.Manifest.permission.ASEC_DESTROY);
San Mehat207e5382010-02-04 20:46:54 -08002257 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002258 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002259
Kenny Rootaa485402010-09-14 14:49:41 -07002260 /*
2261 * Force a GC to make sure AssetManagers in other threads of the
2262 * system_server are cleaned up. We have to do this since AssetManager
2263 * instances are kept as a WeakReference and it's possible we have files
2264 * open on the external storage.
2265 */
2266 Runtime.getRuntime().gc();
2267
San Mehatb1043402010-02-05 08:26:50 -08002268 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002269 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002270 final Command cmd = new Command("asec", "destroy", id);
2271 if (force) {
2272 cmd.appendArg("force");
2273 }
2274 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002275 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002276 int code = e.getCode();
2277 if (code == VoldResponseCode.OpFailedStorageBusy) {
2278 rc = StorageResultCode.OperationFailedStorageBusy;
2279 } else {
2280 rc = StorageResultCode.OperationFailedInternalError;
2281 }
San Mehat02735bc2010-01-26 15:18:08 -08002282 }
San Mehata181b212010-02-11 06:50:20 -08002283
2284 if (rc == StorageResultCode.OperationSucceeded) {
2285 synchronized (mAsecMountSet) {
2286 if (mAsecMountSet.contains(id)) {
2287 mAsecMountSet.remove(id);
2288 }
2289 }
2290 }
2291
San Mehat4270e1e2010-01-29 05:32:19 -08002292 return rc;
San Mehat36972292010-01-06 11:06:32 -08002293 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002294
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002295 public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002296 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002297 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002298 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002299
San Mehata181b212010-02-11 06:50:20 -08002300 synchronized (mAsecMountSet) {
2301 if (mAsecMountSet.contains(id)) {
2302 return StorageResultCode.OperationFailedStorageMounted;
2303 }
2304 }
2305
San Mehatb1043402010-02-05 08:26:50 -08002306 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002307 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002308 mConnector.execute("asec", "mount", id, new SensitiveArg(key), ownerUid,
2309 readOnly ? "ro" : "rw");
San Mehat4270e1e2010-01-29 05:32:19 -08002310 } catch (NativeDaemonConnectorException e) {
Kenny Rootf0304622010-03-19 19:20:42 -07002311 int code = e.getCode();
2312 if (code != VoldResponseCode.OpFailedStorageBusy) {
2313 rc = StorageResultCode.OperationFailedInternalError;
2314 }
San Mehat02735bc2010-01-26 15:18:08 -08002315 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002316
2317 if (rc == StorageResultCode.OperationSucceeded) {
2318 synchronized (mAsecMountSet) {
2319 mAsecMountSet.add(id);
2320 }
2321 }
San Mehat4270e1e2010-01-29 05:32:19 -08002322 return rc;
San Mehat36972292010-01-06 11:06:32 -08002323 }
2324
San Mehatd9709982010-02-18 11:43:03 -08002325 public int unmountSecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002326 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002327 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002328 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002329
San Mehat6cdd9c02010-02-09 14:45:20 -08002330 synchronized (mAsecMountSet) {
2331 if (!mAsecMountSet.contains(id)) {
San Mehata181b212010-02-11 06:50:20 -08002332 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehat6cdd9c02010-02-09 14:45:20 -08002333 }
2334 }
2335
Kenny Rootaa485402010-09-14 14:49:41 -07002336 /*
2337 * Force a GC to make sure AssetManagers in other threads of the
2338 * system_server are cleaned up. We have to do this since AssetManager
2339 * instances are kept as a WeakReference and it's possible we have files
2340 * open on the external storage.
2341 */
2342 Runtime.getRuntime().gc();
2343
San Mehatb1043402010-02-05 08:26:50 -08002344 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002345 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002346 final Command cmd = new Command("asec", "unmount", id);
2347 if (force) {
2348 cmd.appendArg("force");
2349 }
2350 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002351 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002352 int code = e.getCode();
2353 if (code == VoldResponseCode.OpFailedStorageBusy) {
2354 rc = StorageResultCode.OperationFailedStorageBusy;
2355 } else {
2356 rc = StorageResultCode.OperationFailedInternalError;
2357 }
San Mehat02735bc2010-01-26 15:18:08 -08002358 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002359
2360 if (rc == StorageResultCode.OperationSucceeded) {
2361 synchronized (mAsecMountSet) {
2362 mAsecMountSet.remove(id);
2363 }
2364 }
San Mehat4270e1e2010-01-29 05:32:19 -08002365 return rc;
San Mehat9dba7092010-01-18 06:47:41 -08002366 }
2367
San Mehat6cdd9c02010-02-09 14:45:20 -08002368 public boolean isSecureContainerMounted(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002369 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat6cdd9c02010-02-09 14:45:20 -08002370 waitForReady();
2371 warnOnNotMounted();
2372
2373 synchronized (mAsecMountSet) {
2374 return mAsecMountSet.contains(id);
2375 }
2376 }
2377
San Mehat4270e1e2010-01-29 05:32:19 -08002378 public int renameSecureContainer(String oldId, String newId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002379 enforcePermission(android.Manifest.permission.ASEC_RENAME);
San Mehat207e5382010-02-04 20:46:54 -08002380 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002381 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002382
San Mehata181b212010-02-11 06:50:20 -08002383 synchronized (mAsecMountSet) {
San Mehat85451ee2010-02-24 08:54:18 -08002384 /*
Jason parks9ed98bc2011-01-17 09:58:35 -06002385 * Because a mounted container has active internal state which cannot be
San Mehat85451ee2010-02-24 08:54:18 -08002386 * changed while active, we must ensure both ids are not currently mounted.
2387 */
2388 if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
San Mehata181b212010-02-11 06:50:20 -08002389 return StorageResultCode.OperationFailedStorageMounted;
2390 }
2391 }
2392
San Mehatb1043402010-02-05 08:26:50 -08002393 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002394 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002395 mConnector.execute("asec", "rename", oldId, newId);
San Mehat4270e1e2010-01-29 05:32:19 -08002396 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002397 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002398 }
San Mehata181b212010-02-11 06:50:20 -08002399
San Mehat4270e1e2010-01-29 05:32:19 -08002400 return rc;
San Mehat45f61042010-01-23 08:12:43 -08002401 }
2402
San Mehat4270e1e2010-01-29 05:32:19 -08002403 public String getSecureContainerPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002404 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002405 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002406 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002407
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002408 final NativeDaemonEvent event;
San Mehat2d66cef2010-03-23 11:12:52 -07002409 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002410 event = mConnector.execute("asec", "path", id);
2411 event.checkCode(VoldResponseCode.AsecPathResult);
2412 return event.getMessage();
San Mehat2d66cef2010-03-23 11:12:52 -07002413 } catch (NativeDaemonConnectorException e) {
2414 int code = e.getCode();
2415 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Fredrik Helmera20c8ef2011-02-09 16:16:10 +01002416 Slog.i(TAG, String.format("Container '%s' not found", id));
2417 return null;
San Mehat22dd86e2010-01-12 12:21:18 -08002418 } else {
San Mehat2d66cef2010-03-23 11:12:52 -07002419 throw new IllegalStateException(String.format("Unexpected response code %d", code));
San Mehat22dd86e2010-01-12 12:21:18 -08002420 }
2421 }
San Mehat22dd86e2010-01-12 12:21:18 -08002422 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002423
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002424 public String getSecureContainerFilesystemPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002425 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002426 waitForReady();
2427 warnOnNotMounted();
2428
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002429 final NativeDaemonEvent event;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002430 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002431 event = mConnector.execute("asec", "fspath", id);
2432 event.checkCode(VoldResponseCode.AsecPathResult);
2433 return event.getMessage();
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002434 } catch (NativeDaemonConnectorException e) {
2435 int code = e.getCode();
2436 if (code == VoldResponseCode.OpFailedStorageNotFound) {
2437 Slog.i(TAG, String.format("Container '%s' not found", id));
2438 return null;
2439 } else {
2440 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2441 }
2442 }
2443 }
2444
Jeff Sharkey48877892015-03-18 11:27:19 -07002445 @Override
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002446 public void finishMediaUpdate() {
Jeff Sharkey9527b222015-06-24 15:24:48 -07002447 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
Rubin Xucd7a0142015-04-17 23:45:27 +01002448 throw new SecurityException("no permission to call finishMediaUpdate()");
2449 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002450 if (mUnmountSignal != null) {
2451 mUnmountSignal.countDown();
2452 } else {
2453 Slog.w(TAG, "Odd, nobody asked to unmount?");
2454 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002455 }
Kenny Root02c87302010-07-01 08:10:18 -07002456
Kenny Roota02b8b02010-08-05 16:14:17 -07002457 private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
2458 if (callerUid == android.os.Process.SYSTEM_UID) {
2459 return true;
2460 }
2461
Kenny Root02c87302010-07-01 08:10:18 -07002462 if (packageName == null) {
2463 return false;
2464 }
2465
Jeff Sharkeycd654482016-01-08 17:42:11 -07002466 final int packageUid = mPms.getPackageUid(packageName,
2467 PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callerUid));
Kenny Root02c87302010-07-01 08:10:18 -07002468
2469 if (DEBUG_OBB) {
2470 Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
2471 packageUid + ", callerUid = " + callerUid);
2472 }
2473
2474 return callerUid == packageUid;
2475 }
2476
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002477 public String getMountedObbPath(String rawPath) {
2478 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002479
Kenny Root02c87302010-07-01 08:10:18 -07002480 waitForReady();
2481 warnOnNotMounted();
2482
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002483 final ObbState state;
Rubin Xucd7a0142015-04-17 23:45:27 +01002484 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002485 state = mObbPathToStateMap.get(rawPath);
2486 }
2487 if (state == null) {
2488 Slog.w(TAG, "Failed to find OBB mounted at " + rawPath);
2489 return null;
2490 }
2491
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002492 final NativeDaemonEvent event;
Kenny Root02c87302010-07-01 08:10:18 -07002493 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07002494 event = mConnector.execute("obb", "path", state.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002495 event.checkCode(VoldResponseCode.AsecPathResult);
2496 return event.getMessage();
Kenny Root02c87302010-07-01 08:10:18 -07002497 } catch (NativeDaemonConnectorException e) {
2498 int code = e.getCode();
2499 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Kenny Roota02b8b02010-08-05 16:14:17 -07002500 return null;
Kenny Root02c87302010-07-01 08:10:18 -07002501 } else {
2502 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2503 }
2504 }
2505 }
2506
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002507 @Override
2508 public boolean isObbMounted(String rawPath) {
2509 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002510 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002511 return mObbPathToStateMap.containsKey(rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002512 }
Kenny Root02c87302010-07-01 08:10:18 -07002513 }
2514
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002515 @Override
2516 public void mountObb(
2517 String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) {
2518 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2519 Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
2520 Preconditions.checkNotNull(token, "token cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002521
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002522 final int callingUid = Binder.getCallingUid();
2523 final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce);
2524 final ObbAction action = new MountObbAction(obbState, key, callingUid);
Kenny Roota02b8b02010-08-05 16:14:17 -07002525 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
2526
2527 if (DEBUG_OBB)
2528 Slog.i(TAG, "Send to OBB handler: " + action.toString());
Kenny Root02c87302010-07-01 08:10:18 -07002529 }
2530
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002531 @Override
2532 public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
2533 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2534
2535 final ObbState existingState;
Rubin Xucd7a0142015-04-17 23:45:27 +01002536 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002537 existingState = mObbPathToStateMap.get(rawPath);
Kenny Rootf1121dc2010-09-29 07:30:53 -07002538 }
2539
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002540 if (existingState != null) {
2541 // TODO: separate state object from request data
2542 final int callingUid = Binder.getCallingUid();
2543 final ObbState newState = new ObbState(
2544 rawPath, existingState.canonicalPath, callingUid, token, nonce);
2545 final ObbAction action = new UnmountObbAction(newState, force);
2546 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root02c87302010-07-01 08:10:18 -07002547
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002548 if (DEBUG_OBB)
2549 Slog.i(TAG, "Send to OBB handler: " + action.toString());
2550 } else {
2551 Slog.w(TAG, "Unknown OBB mount at " + rawPath);
2552 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002553 }
2554
Ben Komalo444eca22011-09-01 15:17:44 -07002555 @Override
2556 public int getEncryptionState() {
2557 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2558 "no permission to access the crypt keeper");
2559
2560 waitForReady();
2561
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002562 final NativeDaemonEvent event;
Ben Komalo444eca22011-09-01 15:17:44 -07002563 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002564 event = mCryptConnector.execute("cryptfs", "cryptocomplete");
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002565 return Integer.parseInt(event.getMessage());
Ben Komalo444eca22011-09-01 15:17:44 -07002566 } catch (NumberFormatException e) {
2567 // Bad result - unexpected.
2568 Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
Sudheer Shankaf7341142016-10-18 17:15:18 -07002569 return StorageManager.ENCRYPTION_STATE_ERROR_UNKNOWN;
Ben Komalo444eca22011-09-01 15:17:44 -07002570 } catch (NativeDaemonConnectorException e) {
2571 // Something bad happened.
2572 Slog.w(TAG, "Error in communicating with cryptfs in validating");
Sudheer Shankaf7341142016-10-18 17:15:18 -07002573 return StorageManager.ENCRYPTION_STATE_ERROR_UNKNOWN;
Ben Komalo444eca22011-09-01 15:17:44 -07002574 }
2575 }
2576
2577 @Override
Jason parks5af0b912010-11-29 09:05:25 -06002578 public int decryptStorage(String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002579 if (TextUtils.isEmpty(password)) {
2580 throw new IllegalArgumentException("password cannot be empty");
Jason parks5af0b912010-11-29 09:05:25 -06002581 }
2582
Jason parks8888c592011-01-20 22:46:41 -06002583 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2584 "no permission to access the crypt keeper");
Jason parks5af0b912010-11-29 09:05:25 -06002585
2586 waitForReady();
2587
2588 if (DEBUG_EVENTS) {
2589 Slog.i(TAG, "decrypting storage...");
2590 }
2591
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002592 final NativeDaemonEvent event;
Jason parks5af0b912010-11-29 09:05:25 -06002593 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002594 event = mCryptConnector.execute("cryptfs", "checkpw", new SensitiveArg(password));
Jason parks9ed98bc2011-01-17 09:58:35 -06002595
Fredrik Roubertda6aedf2011-12-20 17:34:43 +01002596 final int code = Integer.parseInt(event.getMessage());
Jason parks9ed98bc2011-01-17 09:58:35 -06002597 if (code == 0) {
2598 // Decrypt was successful. Post a delayed message before restarting in order
2599 // to let the UI to clear itself
2600 mHandler.postDelayed(new Runnable() {
2601 public void run() {
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002602 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002603 mCryptConnector.execute("cryptfs", "restart");
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002604 } catch (NativeDaemonConnectorException e) {
2605 Slog.e(TAG, "problem executing in background", e);
2606 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002607 }
Jason parksf7b3cd42011-01-27 09:28:25 -06002608 }, 1000); // 1 second
Jason parks9ed98bc2011-01-17 09:58:35 -06002609 }
2610
2611 return code;
Jason parks5af0b912010-11-29 09:05:25 -06002612 } catch (NativeDaemonConnectorException e) {
2613 // Decryption failed
2614 return e.getCode();
2615 }
Jason parks5af0b912010-11-29 09:05:25 -06002616 }
2617
Paul Lawrence46791e72014-04-03 09:10:26 -07002618 public int encryptStorage(int type, String password) {
2619 if (TextUtils.isEmpty(password) && type != StorageManager.CRYPT_TYPE_DEFAULT) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002620 throw new IllegalArgumentException("password cannot be empty");
Jason parks56aa5322011-01-07 09:01:15 -06002621 }
2622
Jason parks8888c592011-01-20 22:46:41 -06002623 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2624 "no permission to access the crypt keeper");
Jason parks56aa5322011-01-07 09:01:15 -06002625
2626 waitForReady();
2627
2628 if (DEBUG_EVENTS) {
Jason parks8888c592011-01-20 22:46:41 -06002629 Slog.i(TAG, "encrypting storage...");
Jason parks56aa5322011-01-07 09:01:15 -06002630 }
2631
2632 try {
Paul Lawrence5096d9e2015-09-09 13:05:45 -07002633 if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
2634 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2635 CRYPTO_TYPES[type]);
2636 } else {
2637 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2638 CRYPTO_TYPES[type], new SensitiveArg(password));
2639 }
Jason parks56aa5322011-01-07 09:01:15 -06002640 } catch (NativeDaemonConnectorException e) {
2641 // Encryption failed
2642 return e.getCode();
2643 }
2644
2645 return 0;
2646 }
2647
Paul Lawrence8e397362014-01-27 15:22:30 -08002648 /** Set the password for encrypting the master key.
2649 * @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
2650 * @param password The password to set.
2651 */
2652 public int changeEncryptionPassword(int type, String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002653 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2654 "no permission to access the crypt keeper");
2655
2656 waitForReady();
2657
2658 if (DEBUG_EVENTS) {
2659 Slog.i(TAG, "changing encryption password...");
2660 }
2661
2662 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002663 NativeDaemonEvent event = mCryptConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type],
Paul Lawrence05487612015-06-09 13:35:38 -07002664 new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002665 return Integer.parseInt(event.getMessage());
Jason parksf7b3cd42011-01-27 09:28:25 -06002666 } catch (NativeDaemonConnectorException e) {
2667 // Encryption failed
2668 return e.getCode();
2669 }
2670 }
2671
Christopher Tate32418be2011-10-10 13:51:12 -07002672 /**
2673 * Validate a user-supplied password string with cryptfs
2674 */
2675 @Override
2676 public int verifyEncryptionPassword(String password) throws RemoteException {
2677 // Only the system process is permitted to validate passwords
2678 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2679 throw new SecurityException("no permission to access the crypt keeper");
2680 }
2681
2682 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2683 "no permission to access the crypt keeper");
2684
2685 if (TextUtils.isEmpty(password)) {
2686 throw new IllegalArgumentException("password cannot be empty");
2687 }
2688
2689 waitForReady();
2690
2691 if (DEBUG_EVENTS) {
2692 Slog.i(TAG, "validating encryption password...");
2693 }
2694
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002695 final NativeDaemonEvent event;
Christopher Tate32418be2011-10-10 13:51:12 -07002696 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002697 event = mCryptConnector.execute("cryptfs", "verifypw", new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002698 Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
2699 return Integer.parseInt(event.getMessage());
Christopher Tate32418be2011-10-10 13:51:12 -07002700 } catch (NativeDaemonConnectorException e) {
2701 // Encryption failed
2702 return e.getCode();
2703 }
2704 }
2705
Paul Lawrence8e397362014-01-27 15:22:30 -08002706 /**
2707 * Get the type of encryption used to encrypt the master key.
2708 * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
2709 */
2710 @Override
Svetoslav16e4a1a2014-09-29 18:16:20 -07002711 public int getPasswordType() {
Paul Lawrence9de713d2016-05-02 22:45:33 +00002712 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2713 "no permission to access the crypt keeper");
2714
Paul Lawrence8e397362014-01-27 15:22:30 -08002715 waitForReady();
2716
2717 final NativeDaemonEvent event;
2718 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002719 event = mCryptConnector.execute("cryptfs", "getpwtype");
Paul Lawrence8e397362014-01-27 15:22:30 -08002720 for (int i = 0; i < CRYPTO_TYPES.length; ++i) {
2721 if (CRYPTO_TYPES[i].equals(event.getMessage()))
2722 return i;
2723 }
2724
2725 throw new IllegalStateException("unexpected return from cryptfs");
2726 } catch (NativeDaemonConnectorException e) {
2727 throw e.rethrowAsParcelableException();
2728 }
2729 }
2730
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002731 /**
2732 * Set a field in the crypto header.
2733 * @param field field to set
2734 * @param contents contents to set in field
2735 */
2736 @Override
2737 public void setField(String field, String contents) throws RemoteException {
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002738 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2739 "no permission to access the crypt keeper");
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002740
2741 waitForReady();
2742
2743 final NativeDaemonEvent event;
2744 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002745 event = mCryptConnector.execute("cryptfs", "setfield", field, contents);
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002746 } catch (NativeDaemonConnectorException e) {
2747 throw e.rethrowAsParcelableException();
2748 }
2749 }
2750
2751 /**
2752 * Gets a field from the crypto header.
2753 * @param field field to get
2754 * @return contents of field
2755 */
2756 @Override
2757 public String getField(String field) throws RemoteException {
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002758 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2759 "no permission to access the crypt keeper");
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002760
2761 waitForReady();
2762
2763 final NativeDaemonEvent event;
2764 try {
2765 final String[] contents = NativeDaemonEvent.filterMessageList(
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002766 mCryptConnector.executeForList("cryptfs", "getfield", field),
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002767 VoldResponseCode.CryptfsGetfieldResult);
2768 String result = new String();
2769 for (String content : contents) {
2770 result += content;
2771 }
2772 return result;
2773 } catch (NativeDaemonConnectorException e) {
2774 throw e.rethrowAsParcelableException();
2775 }
2776 }
2777
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002778 /**
2779 * Is userdata convertible to file based encryption?
2780 * @return non zero for convertible
2781 */
2782 @Override
2783 public boolean isConvertibleToFBE() throws RemoteException {
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002784 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2785 "no permission to access the crypt keeper");
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002786
2787 waitForReady();
2788
2789 final NativeDaemonEvent event;
2790 try {
2791 event = mCryptConnector.execute("cryptfs", "isConvertibleToFBE");
2792 return Integer.parseInt(event.getMessage()) != 0;
2793 } catch (NativeDaemonConnectorException e) {
2794 throw e.rethrowAsParcelableException();
2795 }
2796 }
2797
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002798 @Override
Paul Lawrence945490c2014-03-27 16:37:28 +00002799 public String getPassword() throws RemoteException {
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002800 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
Rubin Xucd7a0142015-04-17 23:45:27 +01002801 "only keyguard can retrieve password");
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002802
Paul Lawrence945490c2014-03-27 16:37:28 +00002803 if (!isReady()) {
2804 return new String();
2805 }
2806
2807 final NativeDaemonEvent event;
2808 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002809 event = mCryptConnector.execute("cryptfs", "getpw");
Paul Lawrence24063b52015-01-06 13:11:23 -08002810 if ("-1".equals(event.getMessage())) {
2811 // -1 equals no password
2812 return null;
2813 }
Paul Lawrence05487612015-06-09 13:35:38 -07002814 return event.getMessage();
Paul Lawrence945490c2014-03-27 16:37:28 +00002815 } catch (NativeDaemonConnectorException e) {
2816 throw e.rethrowAsParcelableException();
Paul Lawrence24063b52015-01-06 13:11:23 -08002817 } catch (IllegalArgumentException e) {
2818 Slog.e(TAG, "Invalid response to getPassword");
2819 return null;
Paul Lawrence945490c2014-03-27 16:37:28 +00002820 }
2821 }
2822
2823 @Override
2824 public void clearPassword() throws RemoteException {
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002825 mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
2826 "only keyguard can clear password");
2827
Paul Lawrence945490c2014-03-27 16:37:28 +00002828 if (!isReady()) {
2829 return;
2830 }
2831
2832 final NativeDaemonEvent event;
2833 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002834 event = mCryptConnector.execute("cryptfs", "clearpw");
Paul Lawrence945490c2014-03-27 16:37:28 +00002835 } catch (NativeDaemonConnectorException e) {
2836 throw e.rethrowAsParcelableException();
2837 }
2838 }
2839
2840 @Override
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002841 public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002842 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002843 waitForReady();
2844
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002845 try {
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002846 mCryptConnector.execute("cryptfs", "create_user_key", userId, serialNumber,
2847 ephemeral ? 1 : 0);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002848 } catch (NativeDaemonConnectorException e) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002849 throw e.rethrowAsParcelableException();
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002850 }
2851 }
2852
Paul Crowley7ec733f2015-05-19 12:42:00 +01002853 @Override
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002854 public void destroyUserKey(int userId) {
2855 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowley7ec733f2015-05-19 12:42:00 +01002856 waitForReady();
2857
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002858 try {
2859 mCryptConnector.execute("cryptfs", "destroy_user_key", userId);
2860 } catch (NativeDaemonConnectorException e) {
2861 throw e.rethrowAsParcelableException();
2862 }
2863 }
2864
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002865 private SensitiveArg encodeBytes(byte[] bytes) {
2866 if (ArrayUtils.isEmpty(bytes)) {
2867 return new SensitiveArg("!");
2868 } else {
2869 return new SensitiveArg(HexDump.toHexString(bytes));
2870 }
2871 }
2872
Paul Crowleycc701552016-05-17 14:18:49 -07002873 /*
2874 * Add this token/secret pair to the set of ways we can recover a disk encryption key.
2875 * Changing the token/secret for a disk encryption key is done in two phases: first, adding
2876 * a new token/secret pair with this call, then delting all other pairs with
2877 * fixateNewestUserKeyAuth. This allows other places where a credential is used, such as
2878 * Gatekeeper, to be updated between the two calls.
2879 */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002880 @Override
Paul Crowleycc701552016-05-17 14:18:49 -07002881 public void addUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002882 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2883 waitForReady();
2884
2885 try {
Paul Crowleycc701552016-05-17 14:18:49 -07002886 mCryptConnector.execute("cryptfs", "add_user_key_auth", userId, serialNumber,
2887 encodeBytes(token), encodeBytes(secret));
2888 } catch (NativeDaemonConnectorException e) {
2889 throw e.rethrowAsParcelableException();
2890 }
2891 }
2892
2893 /*
2894 * Delete all disk encryption token/secret pairs except the most recently added one
2895 */
2896 @Override
2897 public void fixateNewestUserKeyAuth(int userId) {
2898 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2899 waitForReady();
2900
2901 try {
2902 mCryptConnector.execute("cryptfs", "fixate_newest_user_key_auth", userId);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002903 } catch (NativeDaemonConnectorException e) {
2904 throw e.rethrowAsParcelableException();
2905 }
2906 }
2907
2908 @Override
2909 public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002910 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2911 waitForReady();
2912
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002913 if (StorageManager.isFileEncryptedNativeOrEmulated()) {
2914 // When a user has secure lock screen, require a challenge token to
2915 // actually unlock. This check is mostly in place for emulation mode.
2916 if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(token)) {
2917 throw new IllegalStateException("Token required to unlock secure user " + userId);
2918 }
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07002919
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002920 try {
2921 mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber,
2922 encodeBytes(token), encodeBytes(secret));
2923 } catch (NativeDaemonConnectorException e) {
2924 throw e.rethrowAsParcelableException();
2925 }
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002926 }
2927
2928 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002929 mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002930 }
2931 }
2932
2933 @Override
2934 public void lockUserKey(int userId) {
2935 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2936 waitForReady();
2937
2938 try {
2939 mCryptConnector.execute("cryptfs", "lock_user_key", userId);
2940 } catch (NativeDaemonConnectorException e) {
2941 throw e.rethrowAsParcelableException();
2942 }
2943
2944 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002945 mLocalUnlockedUsers = ArrayUtils.removeInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002946 }
2947 }
2948
2949 @Override
2950 public boolean isUserKeyUnlocked(int userId) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002951 synchronized (mLock) {
2952 return ArrayUtils.contains(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002953 }
2954 }
2955
2956 @Override
Jeff Sharkey47f71082016-02-01 17:03:54 -07002957 public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002958 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2959 waitForReady();
2960
2961 try {
2962 mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid),
Jeff Sharkey47f71082016-02-01 17:03:54 -07002963 userId, serialNumber, flags);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002964 } catch (NativeDaemonConnectorException e) {
2965 throw e.rethrowAsParcelableException();
Paul Crowley7ec733f2015-05-19 12:42:00 +01002966 }
2967 }
2968
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002969 @Override
Jeff Sharkeyfcf1e552016-04-14 20:44:58 -06002970 public void destroyUserStorage(String volumeUuid, int userId, int flags) {
2971 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2972 waitForReady();
2973
2974 try {
2975 mCryptConnector.execute("cryptfs", "destroy_user_storage", escapeNull(volumeUuid),
2976 userId, flags);
2977 } catch (NativeDaemonConnectorException e) {
2978 throw e.rethrowAsParcelableException();
2979 }
2980 }
2981
2982 @Override
Daichi Hirono91e3b502015-12-16 09:24:16 +09002983 public ParcelFileDescriptor mountAppFuse(final String name) throws RemoteException {
Daichi Hironobee50c02015-12-14 11:00:54 +09002984 try {
Daichi Hirono91e3b502015-12-16 09:24:16 +09002985 final int uid = Binder.getCallingUid();
Daichi Hironofd7d57e2016-01-29 14:30:58 +09002986 final int pid = Binder.getCallingPid();
Daichi Hironobee50c02015-12-14 11:00:54 +09002987 final NativeDaemonEvent event =
Daichi Hironofd7d57e2016-01-29 14:30:58 +09002988 mConnector.execute("appfuse", "mount", uid, pid, name);
Daichi Hironobee50c02015-12-14 11:00:54 +09002989 if (event.getFileDescriptors() == null) {
Daichi Hirono91e3b502015-12-16 09:24:16 +09002990 throw new RemoteException("AppFuse FD from vold is null.");
Daichi Hironobee50c02015-12-14 11:00:54 +09002991 }
Daichi Hirono91e3b502015-12-16 09:24:16 +09002992 return ParcelFileDescriptor.fromFd(
2993 event.getFileDescriptors()[0],
2994 mHandler,
2995 new ParcelFileDescriptor.OnCloseListener() {
2996 @Override
2997 public void onClose(IOException e) {
2998 try {
2999 final NativeDaemonEvent event = mConnector.execute(
Daichi Hironofd7d57e2016-01-29 14:30:58 +09003000 "appfuse", "unmount", uid, pid, name);
Daichi Hirono91e3b502015-12-16 09:24:16 +09003001 } catch (NativeDaemonConnectorException unmountException) {
3002 Log.e(TAG, "Failed to unmount appfuse.");
3003 }
3004 }
3005 });
Daichi Hironobee50c02015-12-14 11:00:54 +09003006 } catch (NativeDaemonConnectorException e) {
3007 throw e.rethrowAsParcelableException();
Daichi Hirono91e3b502015-12-16 09:24:16 +09003008 } catch (IOException e) {
3009 throw new RemoteException(e.getMessage());
Daichi Hironobee50c02015-12-14 11:00:54 +09003010 }
Daichi Hirono9e8d9e22015-11-13 14:37:00 +09003011 }
3012
3013 @Override
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003014 public int mkdirs(String callingPkg, String appPath) {
3015 final int userId = UserHandle.getUserId(Binder.getCallingUid());
3016 final UserEnvironment userEnv = new UserEnvironment(userId);
3017
3018 // Validate that reported package name belongs to caller
3019 final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
3020 Context.APP_OPS_SERVICE);
3021 appOps.checkPackage(Binder.getCallingUid(), callingPkg);
3022
Jeff Sharkey48877892015-03-18 11:27:19 -07003023 File appFile = null;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003024 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07003025 appFile = new File(appPath).getCanonicalFile();
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003026 } catch (IOException e) {
3027 Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
3028 return -1;
3029 }
3030
3031 // Try translating the app path into a vold path, but require that it
3032 // belong to the calling package.
Jeff Sharkey48877892015-03-18 11:27:19 -07003033 if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) ||
3034 FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) ||
3035 FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) {
3036 appPath = appFile.getAbsolutePath();
3037 if (!appPath.endsWith("/")) {
3038 appPath = appPath + "/";
3039 }
3040
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003041 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07003042 mConnector.execute("volume", "mkdirs", appPath);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003043 return 0;
3044 } catch (NativeDaemonConnectorException e) {
3045 return e.getCode();
3046 }
3047 }
3048
Jeff Sharkey48877892015-03-18 11:27:19 -07003049 throw new SecurityException("Invalid mkdirs path: " + appFile);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003050 }
3051
3052 @Override
Jeff Sharkey46349872015-07-28 10:49:47 -07003053 public StorageVolume[] getVolumeList(int uid, String packageName, int flags) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003054 final int userId = UserHandle.getUserId(uid);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003055
Jeff Sharkey46349872015-07-28 10:49:47 -07003056 final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0;
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003057 final boolean realState = (flags & StorageManager.FLAG_REAL_STATE) != 0;
3058 final boolean includeInvisible = (flags & StorageManager.FLAG_INCLUDE_INVISIBLE) != 0;
Jeff Sharkey46349872015-07-28 10:49:47 -07003059
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003060 final boolean userKeyUnlocked;
3061 final boolean storagePermission;
3062 final long token = Binder.clearCallingIdentity();
Svetoslav38c3dbb2015-07-14 11:27:06 -07003063 try {
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003064 userKeyUnlocked = isUserKeyUnlocked(userId);
Sudheer Shanka2250d562016-11-07 15:41:02 -08003065 storagePermission = mStorageManagerInternal.hasExternalStorage(uid, packageName);
Svetoslav38c3dbb2015-07-14 11:27:06 -07003066 } finally {
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003067 Binder.restoreCallingIdentity(token);
Svetoslav38c3dbb2015-07-14 11:27:06 -07003068 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003069
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003070 boolean foundPrimary = false;
3071
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003072 final ArrayList<StorageVolume> res = new ArrayList<>();
Jeff Sharkey48877892015-03-18 11:27:19 -07003073 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003074 for (int i = 0; i < mVolumes.size(); i++) {
3075 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003076 switch (vol.getType()) {
3077 case VolumeInfo.TYPE_PUBLIC:
3078 case VolumeInfo.TYPE_EMULATED:
3079 break;
3080 default:
3081 continue;
3082 }
3083
3084 boolean match = false;
3085 if (forWrite) {
3086 match = vol.isVisibleForWrite(userId);
3087 } else {
Felipe Leme123a0e72016-06-10 11:09:11 -07003088 match = vol.isVisibleForRead(userId)
3089 || (includeInvisible && vol.getPath() != null);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003090 }
3091 if (!match) continue;
3092
3093 boolean reportUnmounted = false;
3094 if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !userKeyUnlocked) {
3095 reportUnmounted = true;
3096 } else if (!storagePermission && !realState) {
3097 reportUnmounted = true;
3098 }
3099
3100 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
3101 reportUnmounted);
3102 if (vol.isPrimary()) {
3103 res.add(0, userVol);
3104 foundPrimary = true;
3105 } else {
3106 res.add(userVol);
Jeff Sharkeyb049e212012-09-07 23:16:01 -07003107 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003108 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003109 }
Jeff Sharkey48877892015-03-18 11:27:19 -07003110
3111 if (!foundPrimary) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003112 Log.w(TAG, "No primary storage defined yet; hacking together a stub");
Jeff Sharkey48877892015-03-18 11:27:19 -07003113
3114 final boolean primaryPhysical = SystemProperties.getBoolean(
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003115 StorageManager.PROP_PRIMARY_PHYSICAL, false);
Jeff Sharkey48877892015-03-18 11:27:19 -07003116
3117 final String id = "stub_primary";
3118 final File path = Environment.getLegacyExternalStorageDirectory();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003119 final String description = mContext.getString(android.R.string.unknownName);
Jeff Sharkey48877892015-03-18 11:27:19 -07003120 final boolean primary = true;
3121 final boolean removable = primaryPhysical;
3122 final boolean emulated = !primaryPhysical;
3123 final long mtpReserveSize = 0L;
3124 final boolean allowMassStorage = false;
3125 final long maxFileSize = 0L;
3126 final UserHandle owner = new UserHandle(userId);
3127 final String uuid = null;
Jeff Sharkey48877892015-03-18 11:27:19 -07003128 final String state = Environment.MEDIA_REMOVED;
3129
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07003130 res.add(0, new StorageVolume(id, StorageVolume.STORAGE_ID_INVALID, path,
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003131 description, primary, removable, emulated, mtpReserveSize,
3132 allowMassStorage, maxFileSize, owner, uuid, state));
Jeff Sharkey48877892015-03-18 11:27:19 -07003133 }
3134
3135 return res.toArray(new StorageVolume[res.size()]);
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003136 }
3137
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003138 @Override
3139 public DiskInfo[] getDisks() {
3140 synchronized (mLock) {
3141 final DiskInfo[] res = new DiskInfo[mDisks.size()];
3142 for (int i = 0; i < mDisks.size(); i++) {
3143 res[i] = mDisks.valueAt(i);
3144 }
3145 return res;
3146 }
3147 }
3148
3149 @Override
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003150 public VolumeInfo[] getVolumes(int flags) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003151 synchronized (mLock) {
3152 final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
3153 for (int i = 0; i < mVolumes.size(); i++) {
3154 res[i] = mVolumes.valueAt(i);
3155 }
3156 return res;
3157 }
3158 }
3159
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003160 @Override
3161 public VolumeRecord[] getVolumeRecords(int flags) {
3162 synchronized (mLock) {
3163 final VolumeRecord[] res = new VolumeRecord[mRecords.size()];
3164 for (int i = 0; i < mRecords.size(); i++) {
3165 res[i] = mRecords.valueAt(i);
3166 }
3167 return res;
3168 }
3169 }
3170
Kenny Rootaf9d6672010-10-08 09:21:39 -07003171 private void addObbStateLocked(ObbState obbState) throws RemoteException {
3172 final IBinder binder = obbState.getBinder();
3173 List<ObbState> obbStates = mObbMounts.get(binder);
Kenny Root5919ac62010-10-05 09:49:40 -07003174
Kenny Rootaf9d6672010-10-08 09:21:39 -07003175 if (obbStates == null) {
3176 obbStates = new ArrayList<ObbState>();
3177 mObbMounts.put(binder, obbStates);
3178 } else {
3179 for (final ObbState o : obbStates) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003180 if (o.rawPath.equals(obbState.rawPath)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003181 throw new IllegalStateException("Attempt to add ObbState twice. "
Sudheer Shanka2250d562016-11-07 15:41:02 -08003182 + "This indicates an error in the StorageManagerService logic.");
Kenny Root5919ac62010-10-05 09:49:40 -07003183 }
3184 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003185 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003186
3187 obbStates.add(obbState);
3188 try {
3189 obbState.link();
3190 } catch (RemoteException e) {
3191 /*
3192 * The binder died before we could link it, so clean up our state
3193 * and return failure.
3194 */
3195 obbStates.remove(obbState);
3196 if (obbStates.isEmpty()) {
3197 mObbMounts.remove(binder);
3198 }
3199
3200 // Rethrow the error so mountObb can get it
3201 throw e;
3202 }
3203
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003204 mObbPathToStateMap.put(obbState.rawPath, obbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003205 }
3206
Kenny Rootaf9d6672010-10-08 09:21:39 -07003207 private void removeObbStateLocked(ObbState obbState) {
3208 final IBinder binder = obbState.getBinder();
3209 final List<ObbState> obbStates = mObbMounts.get(binder);
3210 if (obbStates != null) {
3211 if (obbStates.remove(obbState)) {
3212 obbState.unlink();
Kenny Root05105f72010-09-22 17:29:43 -07003213 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003214 if (obbStates.isEmpty()) {
3215 mObbMounts.remove(binder);
3216 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003217 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003218
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003219 mObbPathToStateMap.remove(obbState.rawPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003220 }
3221
Kenny Roota02b8b02010-08-05 16:14:17 -07003222 private class ObbActionHandler extends Handler {
3223 private boolean mBound = false;
Kenny Root480afe72010-10-07 10:17:50 -07003224 private final List<ObbAction> mActions = new LinkedList<ObbAction>();
Kenny Roota02b8b02010-08-05 16:14:17 -07003225
3226 ObbActionHandler(Looper l) {
3227 super(l);
3228 }
3229
3230 @Override
3231 public void handleMessage(Message msg) {
3232 switch (msg.what) {
3233 case OBB_RUN_ACTION: {
Kenny Root480afe72010-10-07 10:17:50 -07003234 final ObbAction action = (ObbAction) msg.obj;
Kenny Roota02b8b02010-08-05 16:14:17 -07003235
3236 if (DEBUG_OBB)
3237 Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
3238
3239 // If a bind was already initiated we don't really
3240 // need to do anything. The pending install
3241 // will be processed later on.
3242 if (!mBound) {
3243 // If this is the only one pending we might
3244 // have to bind to the service again.
3245 if (!connectToService()) {
3246 Slog.e(TAG, "Failed to bind to media container service");
3247 action.handleError();
3248 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003249 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003250 }
Kenny Root735de3b2010-09-30 14:11:39 -07003251
Kenny Root735de3b2010-09-30 14:11:39 -07003252 mActions.add(action);
Kenny Roota02b8b02010-08-05 16:14:17 -07003253 break;
3254 }
3255 case OBB_MCS_BOUND: {
3256 if (DEBUG_OBB)
3257 Slog.i(TAG, "OBB_MCS_BOUND");
3258 if (msg.obj != null) {
3259 mContainerService = (IMediaContainerService) msg.obj;
3260 }
3261 if (mContainerService == null) {
3262 // Something seriously wrong. Bail out
3263 Slog.e(TAG, "Cannot bind to media container service");
3264 for (ObbAction action : mActions) {
3265 // Indicate service bind error
3266 action.handleError();
3267 }
3268 mActions.clear();
3269 } else if (mActions.size() > 0) {
Kenny Root480afe72010-10-07 10:17:50 -07003270 final ObbAction action = mActions.get(0);
Kenny Roota02b8b02010-08-05 16:14:17 -07003271 if (action != null) {
3272 action.execute(this);
3273 }
3274 } else {
3275 // Should never happen ideally.
3276 Slog.w(TAG, "Empty queue");
3277 }
3278 break;
3279 }
3280 case OBB_MCS_RECONNECT: {
3281 if (DEBUG_OBB)
3282 Slog.i(TAG, "OBB_MCS_RECONNECT");
3283 if (mActions.size() > 0) {
3284 if (mBound) {
3285 disconnectService();
3286 }
3287 if (!connectToService()) {
3288 Slog.e(TAG, "Failed to bind to media container service");
3289 for (ObbAction action : mActions) {
3290 // Indicate service bind error
3291 action.handleError();
3292 }
3293 mActions.clear();
3294 }
3295 }
3296 break;
3297 }
3298 case OBB_MCS_UNBIND: {
3299 if (DEBUG_OBB)
3300 Slog.i(TAG, "OBB_MCS_UNBIND");
3301
3302 // Delete pending install
3303 if (mActions.size() > 0) {
3304 mActions.remove(0);
3305 }
3306 if (mActions.size() == 0) {
3307 if (mBound) {
3308 disconnectService();
3309 }
3310 } else {
3311 // There are more pending requests in queue.
3312 // Just post MCS_BOUND message to trigger processing
3313 // of next pending install.
3314 mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
3315 }
3316 break;
3317 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003318 case OBB_FLUSH_MOUNT_STATE: {
3319 final String path = (String) msg.obj;
3320
3321 if (DEBUG_OBB)
3322 Slog.i(TAG, "Flushing all OBB state for path " + path);
3323
3324 synchronized (mObbMounts) {
3325 final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
3326
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003327 final Iterator<ObbState> i = mObbPathToStateMap.values().iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003328 while (i.hasNext()) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003329 final ObbState state = i.next();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003330
3331 /*
3332 * If this entry's source file is in the volume path
3333 * that got unmounted, remove it because it's no
3334 * longer valid.
3335 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003336 if (state.canonicalPath.startsWith(path)) {
3337 obbStatesToRemove.add(state);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003338 }
3339 }
3340
3341 for (final ObbState obbState : obbStatesToRemove) {
3342 if (DEBUG_OBB)
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003343 Slog.i(TAG, "Removing state for " + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003344
3345 removeObbStateLocked(obbState);
3346
3347 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003348 obbState.token.onObbResult(obbState.rawPath, obbState.nonce,
Kenny Rootaf9d6672010-10-08 09:21:39 -07003349 OnObbStateChangeListener.UNMOUNTED);
3350 } catch (RemoteException e) {
3351 Slog.i(TAG, "Couldn't send unmount notification for OBB: "
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003352 + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003353 }
3354 }
3355 }
3356 break;
3357 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003358 }
3359 }
3360
3361 private boolean connectToService() {
3362 if (DEBUG_OBB)
3363 Slog.i(TAG, "Trying to bind to DefaultContainerService");
3364
3365 Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Jeff Sharkey6dce4962015-07-03 18:08:41 -07003366 if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE,
Xiaohui Chene4de5a02015-09-22 15:33:31 -07003367 UserHandle.SYSTEM)) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003368 mBound = true;
3369 return true;
3370 }
3371 return false;
3372 }
3373
3374 private void disconnectService() {
3375 mContainerService = null;
3376 mBound = false;
3377 mContext.unbindService(mDefContainerConn);
3378 }
3379 }
3380
3381 abstract class ObbAction {
3382 private static final int MAX_RETRIES = 3;
3383 private int mRetries;
3384
3385 ObbState mObbState;
3386
3387 ObbAction(ObbState obbState) {
3388 mObbState = obbState;
3389 }
3390
3391 public void execute(ObbActionHandler handler) {
3392 try {
3393 if (DEBUG_OBB)
Ben Komalo444eca22011-09-01 15:17:44 -07003394 Slog.i(TAG, "Starting to execute action: " + toString());
Kenny Roota02b8b02010-08-05 16:14:17 -07003395 mRetries++;
3396 if (mRetries > MAX_RETRIES) {
3397 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
Kenny Root480afe72010-10-07 10:17:50 -07003398 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003399 handleError();
Kenny Roota02b8b02010-08-05 16:14:17 -07003400 } else {
3401 handleExecute();
3402 if (DEBUG_OBB)
3403 Slog.i(TAG, "Posting install MCS_UNBIND");
3404 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
3405 }
3406 } catch (RemoteException e) {
3407 if (DEBUG_OBB)
3408 Slog.i(TAG, "Posting install MCS_RECONNECT");
3409 mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
3410 } catch (Exception e) {
3411 if (DEBUG_OBB)
3412 Slog.d(TAG, "Error handling OBB action", e);
3413 handleError();
Kenny Root17eb6fb2010-10-06 15:02:52 -07003414 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003415 }
3416 }
3417
Kenny Root05105f72010-09-22 17:29:43 -07003418 abstract void handleExecute() throws RemoteException, IOException;
Kenny Roota02b8b02010-08-05 16:14:17 -07003419 abstract void handleError();
Kenny Root38cf8862010-09-26 14:18:51 -07003420
3421 protected ObbInfo getObbInfo() throws IOException {
3422 ObbInfo obbInfo;
3423 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003424 obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003425 } catch (RemoteException e) {
3426 Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003427 + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003428 obbInfo = null;
3429 }
3430 if (obbInfo == null) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003431 throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003432 }
3433 return obbInfo;
3434 }
3435
Kenny Rootaf9d6672010-10-08 09:21:39 -07003436 protected void sendNewStatusOrIgnore(int status) {
3437 if (mObbState == null || mObbState.token == null) {
3438 return;
3439 }
3440
Kenny Root38cf8862010-09-26 14:18:51 -07003441 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003442 mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
Kenny Root38cf8862010-09-26 14:18:51 -07003443 } catch (RemoteException e) {
Sudheer Shanka2250d562016-11-07 15:41:02 -08003444 Slog.w(TAG, "StorageEventListener went away while calling onObbStateChanged");
Kenny Root38cf8862010-09-26 14:18:51 -07003445 }
3446 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003447 }
3448
3449 class MountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003450 private final String mKey;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003451 private final int mCallingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003452
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003453 MountObbAction(ObbState obbState, String key, int callingUid) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003454 super(obbState);
3455 mKey = key;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003456 mCallingUid = callingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003457 }
3458
Jason parks5af0b912010-11-29 09:05:25 -06003459 @Override
Kenny Root735de3b2010-09-30 14:11:39 -07003460 public void handleExecute() throws IOException, RemoteException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003461 waitForReady();
3462 warnOnNotMounted();
3463
Kenny Root38cf8862010-09-26 14:18:51 -07003464 final ObbInfo obbInfo = getObbInfo();
3465
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003466 if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003467 Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
3468 + " which is owned by " + obbInfo.packageName);
3469 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3470 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003471 }
3472
Kenny Rootaf9d6672010-10-08 09:21:39 -07003473 final boolean isMounted;
3474 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003475 isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003476 }
3477 if (isMounted) {
3478 Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
3479 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
3480 return;
3481 }
3482
Kenny Rootaf9d6672010-10-08 09:21:39 -07003483 final String hashedKey;
3484 if (mKey == null) {
3485 hashedKey = "none";
3486 } else {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003487 try {
Kenny Root3b1abba2010-10-13 15:00:07 -07003488 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
3489
3490 KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
3491 PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
3492 SecretKey key = factory.generateSecret(ks);
3493 BigInteger bi = new BigInteger(key.getEncoded());
3494 hashedKey = bi.toString(16);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003495 } catch (NoSuchAlgorithmException e) {
Kenny Root3b1abba2010-10-13 15:00:07 -07003496 Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
3497 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
3498 return;
3499 } catch (InvalidKeySpecException e) {
3500 Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
3501 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root38cf8862010-09-26 14:18:51 -07003502 return;
3503 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003504 }
Kenny Root38cf8862010-09-26 14:18:51 -07003505
Kenny Rootaf9d6672010-10-08 09:21:39 -07003506 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003507 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003508 mConnector.execute("obb", "mount", mObbState.canonicalPath, new SensitiveArg(hashedKey),
Jeff Sharkey56cd6462013-06-07 15:09:15 -07003509 mObbState.ownerGid);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003510 } catch (NativeDaemonConnectorException e) {
3511 int code = e.getCode();
3512 if (code != VoldResponseCode.OpFailedStorageBusy) {
3513 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003514 }
3515 }
3516
Kenny Rootaf9d6672010-10-08 09:21:39 -07003517 if (rc == StorageResultCode.OperationSucceeded) {
3518 if (DEBUG_OBB)
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003519 Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003520
3521 synchronized (mObbMounts) {
3522 addObbStateLocked(mObbState);
3523 }
3524
3525 sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
Kenny Root02c87302010-07-01 08:10:18 -07003526 } else {
Kenny Root05105f72010-09-22 17:29:43 -07003527 Slog.e(TAG, "Couldn't mount OBB file: " + rc);
Kenny Roota02b8b02010-08-05 16:14:17 -07003528
Kenny Rootaf9d6672010-10-08 09:21:39 -07003529 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
Kenny Root02c87302010-07-01 08:10:18 -07003530 }
3531 }
3532
Jason parks5af0b912010-11-29 09:05:25 -06003533 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003534 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003535 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root02c87302010-07-01 08:10:18 -07003536 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003537
3538 @Override
3539 public String toString() {
3540 StringBuilder sb = new StringBuilder();
3541 sb.append("MountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003542 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003543 sb.append('}');
3544 return sb.toString();
3545 }
3546 }
3547
3548 class UnmountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003549 private final boolean mForceUnmount;
Kenny Roota02b8b02010-08-05 16:14:17 -07003550
3551 UnmountObbAction(ObbState obbState, boolean force) {
3552 super(obbState);
3553 mForceUnmount = force;
3554 }
3555
Jason parks5af0b912010-11-29 09:05:25 -06003556 @Override
Kenny Root38cf8862010-09-26 14:18:51 -07003557 public void handleExecute() throws IOException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003558 waitForReady();
3559 warnOnNotMounted();
3560
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003561 final ObbState existingState;
Kenny Root38cf8862010-09-26 14:18:51 -07003562 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003563 existingState = mObbPathToStateMap.get(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003564 }
Kenny Root38cf8862010-09-26 14:18:51 -07003565
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003566 if (existingState == null) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003567 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
3568 return;
3569 }
3570
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003571 if (existingState.ownerGid != mObbState.ownerGid) {
3572 Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
3573 + " (owned by GID " + existingState.ownerGid + ")");
Kenny Rootaf9d6672010-10-08 09:21:39 -07003574 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3575 return;
3576 }
3577
Kenny Rootaf9d6672010-10-08 09:21:39 -07003578 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003579 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003580 final Command cmd = new Command("obb", "unmount", mObbState.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08003581 if (mForceUnmount) {
3582 cmd.appendArg("force");
3583 }
3584 mConnector.execute(cmd);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003585 } catch (NativeDaemonConnectorException e) {
3586 int code = e.getCode();
3587 if (code == VoldResponseCode.OpFailedStorageBusy) {
3588 rc = StorageResultCode.OperationFailedStorageBusy;
3589 } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
3590 // If it's not mounted then we've already won.
3591 rc = StorageResultCode.OperationSucceeded;
3592 } else {
3593 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003594 }
3595 }
3596
Kenny Rootaf9d6672010-10-08 09:21:39 -07003597 if (rc == StorageResultCode.OperationSucceeded) {
3598 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003599 removeObbStateLocked(existingState);
Kenny Root38cf8862010-09-26 14:18:51 -07003600 }
3601
Kenny Rootaf9d6672010-10-08 09:21:39 -07003602 sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
Kenny Roota02b8b02010-08-05 16:14:17 -07003603 } else {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003604 Slog.w(TAG, "Could not unmount OBB: " + existingState);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003605 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
Kenny Roota02b8b02010-08-05 16:14:17 -07003606 }
3607 }
3608
Jason parks5af0b912010-11-29 09:05:25 -06003609 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003610 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003611 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Roota02b8b02010-08-05 16:14:17 -07003612 }
3613
3614 @Override
3615 public String toString() {
3616 StringBuilder sb = new StringBuilder();
3617 sb.append("UnmountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003618 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003619 sb.append(",force=");
3620 sb.append(mForceUnmount);
Kenny Roota02b8b02010-08-05 16:14:17 -07003621 sb.append('}');
3622 return sb.toString();
3623 }
Kenny Root02c87302010-07-01 08:10:18 -07003624 }
Kenny Root38cf8862010-09-26 14:18:51 -07003625
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003626 private static class Callbacks extends Handler {
3627 private static final int MSG_STORAGE_STATE_CHANGED = 1;
3628 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003629 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
3630 private static final int MSG_VOLUME_FORGOTTEN = 4;
3631 private static final int MSG_DISK_SCANNED = 5;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003632 private static final int MSG_DISK_DESTROYED = 6;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003633
Sudheer Shanka2250d562016-11-07 15:41:02 -08003634 private final RemoteCallbackList<IStorageEventListener>
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003635 mCallbacks = new RemoteCallbackList<>();
3636
3637 public Callbacks(Looper looper) {
3638 super(looper);
3639 }
3640
Sudheer Shanka2250d562016-11-07 15:41:02 -08003641 public void register(IStorageEventListener callback) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003642 mCallbacks.register(callback);
3643 }
3644
Sudheer Shanka2250d562016-11-07 15:41:02 -08003645 public void unregister(IStorageEventListener callback) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003646 mCallbacks.unregister(callback);
3647 }
3648
3649 @Override
3650 public void handleMessage(Message msg) {
3651 final SomeArgs args = (SomeArgs) msg.obj;
3652 final int n = mCallbacks.beginBroadcast();
3653 for (int i = 0; i < n; i++) {
Sudheer Shanka2250d562016-11-07 15:41:02 -08003654 final IStorageEventListener callback = mCallbacks.getBroadcastItem(i);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003655 try {
3656 invokeCallback(callback, msg.what, args);
3657 } catch (RemoteException ignored) {
3658 }
3659 }
3660 mCallbacks.finishBroadcast();
3661 args.recycle();
3662 }
3663
Sudheer Shanka2250d562016-11-07 15:41:02 -08003664 private void invokeCallback(IStorageEventListener callback, int what, SomeArgs args)
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003665 throws RemoteException {
3666 switch (what) {
3667 case MSG_STORAGE_STATE_CHANGED: {
3668 callback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
3669 (String) args.arg3);
3670 break;
3671 }
3672 case MSG_VOLUME_STATE_CHANGED: {
3673 callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
3674 break;
3675 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07003676 case MSG_VOLUME_RECORD_CHANGED: {
3677 callback.onVolumeRecordChanged((VolumeRecord) args.arg1);
3678 break;
3679 }
3680 case MSG_VOLUME_FORGOTTEN: {
3681 callback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003682 break;
3683 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003684 case MSG_DISK_SCANNED: {
3685 callback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003686 break;
3687 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003688 case MSG_DISK_DESTROYED: {
3689 callback.onDiskDestroyed((DiskInfo) args.arg1);
3690 break;
3691 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003692 }
3693 }
3694
3695 private void notifyStorageStateChanged(String path, String oldState, String newState) {
3696 final SomeArgs args = SomeArgs.obtain();
3697 args.arg1 = path;
3698 args.arg2 = oldState;
3699 args.arg3 = newState;
3700 obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
3701 }
3702
3703 private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
3704 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003705 args.arg1 = vol.clone();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003706 args.argi2 = oldState;
3707 args.argi3 = newState;
3708 obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
3709 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003710
Jeff Sharkey50a05452015-04-29 11:24:52 -07003711 private void notifyVolumeRecordChanged(VolumeRecord rec) {
3712 final SomeArgs args = SomeArgs.obtain();
3713 args.arg1 = rec.clone();
3714 obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
3715 }
3716
3717 private void notifyVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003718 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003719 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003720 obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003721 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003722
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003723 private void notifyDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003724 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003725 args.arg1 = disk.clone();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003726 args.argi2 = volumeCount;
3727 obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003728 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003729
3730 private void notifyDiskDestroyed(DiskInfo disk) {
3731 final SomeArgs args = SomeArgs.obtain();
3732 args.arg1 = disk.clone();
3733 obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
3734 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003735 }
3736
Kenny Root38cf8862010-09-26 14:18:51 -07003737 @Override
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003738 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
3739 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
3740
3741 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003742 synchronized (mLock) {
3743 pw.println("Disks:");
3744 pw.increaseIndent();
3745 for (int i = 0; i < mDisks.size(); i++) {
3746 final DiskInfo disk = mDisks.valueAt(i);
3747 disk.dump(pw);
3748 }
3749 pw.decreaseIndent();
3750
3751 pw.println();
3752 pw.println("Volumes:");
3753 pw.increaseIndent();
3754 for (int i = 0; i < mVolumes.size(); i++) {
3755 final VolumeInfo vol = mVolumes.valueAt(i);
3756 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue;
3757 vol.dump(pw);
3758 }
3759 pw.decreaseIndent();
3760
3761 pw.println();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003762 pw.println("Records:");
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003763 pw.increaseIndent();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003764 for (int i = 0; i < mRecords.size(); i++) {
3765 final VolumeRecord note = mRecords.valueAt(i);
3766 note.dump(pw);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003767 }
3768 pw.decreaseIndent();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07003769
3770 pw.println();
3771 pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
Felipe Leme281389a2016-10-10 17:12:20 -07003772 final Pair<String, Long> pair = StorageManager.getPrimaryStoragePathAndSize();
3773 if (pair == null) {
3774 pw.println("Internal storage total size: N/A");
3775 } else {
3776 pw.print("Internal storage (");
3777 pw.print(pair.first);
3778 pw.print(") total size: ");
3779 pw.print(pair.second);
3780 pw.print(" (");
3781 pw.print((float) pair.second / TrafficStats.GB_IN_BYTES);
3782 pw.println(" GB)");
3783 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07003784 pw.println("Force adoptable: " + mForceAdoptable);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08003785 pw.println();
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003786 pw.println("Local unlocked users: " + Arrays.toString(mLocalUnlockedUsers));
3787 pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003788 }
Kenny Root38cf8862010-09-26 14:18:51 -07003789
Kenny Root38cf8862010-09-26 14:18:51 -07003790 synchronized (mObbMounts) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003791 pw.println();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003792 pw.println("mObbMounts:");
3793 pw.increaseIndent();
3794 final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet()
3795 .iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003796 while (binders.hasNext()) {
3797 Entry<IBinder, List<ObbState>> e = binders.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003798 pw.println(e.getKey() + ":");
3799 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003800 final List<ObbState> obbStates = e.getValue();
Kenny Root38cf8862010-09-26 14:18:51 -07003801 for (final ObbState obbState : obbStates) {
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003802 pw.println(obbState);
Kenny Root38cf8862010-09-26 14:18:51 -07003803 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003804 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003805 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003806 pw.decreaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003807
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003808 pw.println();
3809 pw.println("mObbPathToStateMap:");
3810 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003811 final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
3812 while (maps.hasNext()) {
3813 final Entry<String, ObbState> e = maps.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003814 pw.print(e.getKey());
3815 pw.print(" -> ");
3816 pw.println(e.getValue());
Kenny Rootaf9d6672010-10-08 09:21:39 -07003817 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003818 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003819 }
Kenny Root4161f9b2011-07-13 09:48:33 -07003820
Robert Greenwalt470fd722012-01-18 12:51:15 -08003821 pw.println();
Jeff Sharkey5b0e5202015-12-18 17:18:09 -07003822 pw.println("mConnector:");
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003823 pw.increaseIndent();
Robert Greenwalt470fd722012-01-18 12:51:15 -08003824 mConnector.dump(fd, pw, args);
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003825 pw.decreaseIndent();
Christopher Tate7265abe2014-11-21 13:54:45 -08003826
Christopher Tate7265abe2014-11-21 13:54:45 -08003827 pw.println();
Jeff Sharkey5b0e5202015-12-18 17:18:09 -07003828 pw.println("mCryptConnector:");
3829 pw.increaseIndent();
3830 mCryptConnector.dump(fd, pw, args);
3831 pw.decreaseIndent();
3832
3833 pw.println();
Christopher Tate7265abe2014-11-21 13:54:45 -08003834 pw.print("Last maintenance: ");
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07003835 pw.println(TimeUtils.formatForLogging(mLastMaintenance));
Kenny Root38cf8862010-09-26 14:18:51 -07003836 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003837
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003838 /** {@inheritDoc} */
Jeff Sharkey48877892015-03-18 11:27:19 -07003839 @Override
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003840 public void monitor() {
3841 if (mConnector != null) {
3842 mConnector.monitor();
3843 }
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07003844 if (mCryptConnector != null) {
3845 mCryptConnector.monitor();
3846 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003847 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003848
Sudheer Shanka2250d562016-11-07 15:41:02 -08003849 private final class StorageManagerInternalImpl extends StorageManagerInternal {
Svet Ganov6ee871e2015-07-10 14:29:33 -07003850 // Not guarded by a lock.
3851 private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
3852 new CopyOnWriteArrayList<>();
3853
3854 @Override
3855 public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
3856 // No locking - CopyOnWriteArrayList
3857 mPolicies.add(policy);
3858 }
3859
3860 @Override
3861 public void onExternalStoragePolicyChanged(int uid, String packageName) {
3862 final int mountMode = getExternalStorageMountMode(uid, packageName);
3863 remountUidExternalStorage(uid, mountMode);
3864 }
3865
3866 @Override
3867 public int getExternalStorageMountMode(int uid, String packageName) {
3868 // No locking - CopyOnWriteArrayList
3869 int mountMode = Integer.MAX_VALUE;
3870 for (ExternalStorageMountPolicy policy : mPolicies) {
3871 final int policyMode = policy.getMountMode(uid, packageName);
3872 if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
3873 return Zygote.MOUNT_EXTERNAL_NONE;
3874 }
3875 mountMode = Math.min(mountMode, policyMode);
3876 }
3877 if (mountMode == Integer.MAX_VALUE) {
3878 return Zygote.MOUNT_EXTERNAL_NONE;
3879 }
3880 return mountMode;
3881 }
3882
3883 public boolean hasExternalStorage(int uid, String packageName) {
Amith Yamasani2bd5cff2015-07-22 14:42:31 -07003884 // No need to check for system uid. This avoids a deadlock between
3885 // PackageManagerService and AppOpsService.
3886 if (uid == Process.SYSTEM_UID) {
3887 return true;
3888 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003889 // No locking - CopyOnWriteArrayList
3890 for (ExternalStorageMountPolicy policy : mPolicies) {
3891 final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
3892 if (!policyHasStorage) {
3893 return false;
3894 }
3895 }
3896 return true;
3897 }
3898 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07003899}