blob: cffb158a3f21e3e68740715bb689a7093f2e7ccd [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 Sharkey9bed0702017-01-23 20:37:05 -070036import android.app.usage.StorageStatsManager;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070037import android.content.BroadcastReceiver;
Kenny Roota02b8b02010-08-05 16:14:17 -070038import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.content.Context;
40import android.content.Intent;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070041import android.content.IntentFilter;
Kenny Roota02b8b02010-08-05 16:14:17 -070042import android.content.ServiceConnection;
Jeff Sharkey275e3e42015-04-24 16:10:32 -070043import android.content.pm.IPackageMoveObserver;
44import android.content.pm.PackageManager;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070045import android.content.pm.ProviderInfo;
Jeff Sharkeybcd262d2015-06-10 09:41:17 -070046import android.content.pm.UserInfo;
Elliott Hughesf839b4f2014-09-26 12:30:47 -070047import android.content.res.Configuration;
Kenny Root02c87302010-07-01 08:10:18 -070048import android.content.res.ObbInfo;
Felipe Leme281389a2016-10-10 17:12:20 -070049import android.net.TrafficStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.net.Uri;
Kenny Root02c87302010-07-01 08:10:18 -070051import android.os.Binder;
Jeff Sharkey4c099d02015-05-15 13:45:00 -070052import android.os.DropBoxManager;
Kenny Roota02b8b02010-08-05 16:14:17 -070053import android.os.Environment;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070054import android.os.Environment.UserEnvironment;
Jeff Sharkey48877892015-03-18 11:27:19 -070055import android.os.FileUtils;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080056import android.os.Handler;
Dianne Hackbornefa92b22013-05-03 14:11:43 -070057import android.os.HandlerThread;
Kenny Roota02b8b02010-08-05 16:14:17 -070058import android.os.IBinder;
Daniel Sandler5f27ef42010-03-16 15:42:02 -040059import android.os.Looper;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -080060import android.os.Message;
Daichi Hirono9e8d9e22015-11-13 14:37:00 +090061import android.os.ParcelFileDescriptor;
Jeff Sharkey500ce9e2017-02-12 02:39:24 -070062import android.os.ParcelableException;
Jeff Sharkeyce14cd02015-12-07 15:35:42 -070063import android.os.PowerManager;
Jeff Sharkey9527b222015-06-24 15:24:48 -070064import android.os.Process;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -070065import android.os.RemoteCallbackList;
San Mehat4270e1e2010-01-29 05:32:19 -080066import android.os.RemoteException;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -080067import android.os.ServiceManager;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -070068import android.os.SystemClock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070070import android.os.UserHandle;
Emily Bernier92aa5a22014-07-07 10:11:48 -040071import android.os.UserManager;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070072import android.os.storage.DiskInfo;
Kenny Roota02b8b02010-08-05 16:14:17 -070073import android.os.storage.IObbActionListener;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070074import android.os.storage.IStorageEventListener;
Sudheer Shanka2250d562016-11-07 15:41:02 -080075import android.os.storage.IStorageManager;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070076import android.os.storage.IStorageShutdownObserver;
Kenny Rootaf9d6672010-10-08 09:21:39 -070077import android.os.storage.OnObbStateChangeListener;
Paul Lawrence46791e72014-04-03 09:10:26 -070078import android.os.storage.StorageManager;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -070079import android.os.storage.StorageManagerInternal;
Kenny Roota02b8b02010-08-05 16:14:17 -070080import android.os.storage.StorageResultCode;
Mike Lockwood2f6a3882011-05-09 19:08:06 -070081import android.os.storage.StorageVolume;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070082import android.os.storage.VolumeInfo;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -070083import android.os.storage.VolumeRecord;
Jeff Sharkey14cbe522015-07-08 14:06:37 -070084import android.provider.MediaStore;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070085import android.provider.Settings;
Jason parksf7b3cd42011-01-27 09:28:25 -060086import android.text.TextUtils;
Jeff Sharkey1783f142015-04-17 10:52:51 -070087import android.text.format.DateUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -070088import android.util.ArrayMap;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070089import android.util.AtomicFile;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -070090import android.util.Log;
Felipe Leme281389a2016-10-10 17:12:20 -070091import android.util.Pair;
San Mehata5078592010-03-25 09:36:54 -070092import android.util.Slog;
Daichi Hirono9fb00182016-11-08 14:12:17 +090093import android.util.SparseArray;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -070094import android.util.TimeUtils;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -070095import android.util.Xml;
Jeff Sharkey48877892015-03-18 11:27:19 -070096
Jeff Sharkey8b2c3a142012-11-12 11:45:05 -080097import com.android.internal.annotations.GuardedBy;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070098import com.android.internal.app.IMediaContainerService;
Daichi Hirono9fb00182016-11-08 14:12:17 +090099import com.android.internal.os.AppFuseMount;
Daichi Hironoe56740d2017-02-02 13:56:45 +0900100import com.android.internal.os.FuseAppLoop;
Daichi Hirono812c95d2017-02-08 16:20:20 +0900101import com.android.internal.os.FuseUnavailableMountException;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700102import com.android.internal.os.SomeArgs;
Jeff Sharkey9527b222015-06-24 15:24:48 -0700103import com.android.internal.os.Zygote;
Jeff Sharkey48877892015-03-18 11:27:19 -0700104import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600105import com.android.internal.util.DumpUtils;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700106import com.android.internal.util.FastXmlSerializer;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800107import com.android.internal.util.HexDump;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -0700108import com.android.internal.util.IndentingPrintWriter;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700109import com.android.internal.util.Preconditions;
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700110import com.android.internal.widget.LockPatternUtils;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700111import com.android.server.NativeDaemonConnector.Command;
Jeff Sharkey56cd6462013-06-07 15:09:15 -0700112import com.android.server.NativeDaemonConnector.SensitiveArg;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700113import com.android.server.pm.PackageManagerService;
Daichi Hirono9fb00182016-11-08 14:12:17 +0900114import com.android.server.storage.AppFuseBridge;
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -0700115
Jeff Sharkey5217cac2015-12-20 15:34:01 -0700116import libcore.io.IoUtils;
117import libcore.util.EmptyArray;
118
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700119import org.xmlpull.v1.XmlPullParser;
120import org.xmlpull.v1.XmlPullParserException;
121import org.xmlpull.v1.XmlSerializer;
122
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700123import java.io.File;
Kenny Root38cf8862010-09-26 14:18:51 -0700124import java.io.FileDescriptor;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700125import java.io.FileInputStream;
126import java.io.FileNotFoundException;
Christopher Tate7265abe2014-11-21 13:54:45 -0800127import java.io.FileOutputStream;
Kenny Root05105f72010-09-22 17:29:43 -0700128import java.io.IOException;
Kenny Root38cf8862010-09-26 14:18:51 -0700129import java.io.PrintWriter;
Kenny Root3b1abba2010-10-13 15:00:07 -0700130import java.math.BigInteger;
Paul Lawrence8e397362014-01-27 15:22:30 -0800131import java.nio.charset.StandardCharsets;
Kenny Root735de3b2010-09-30 14:11:39 -0700132import java.security.NoSuchAlgorithmException;
Kenny Root3b1abba2010-10-13 15:00:07 -0700133import java.security.spec.InvalidKeySpecException;
134import java.security.spec.KeySpec;
San Mehat22dd86e2010-01-12 12:21:18 -0800135import java.util.ArrayList;
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800136import java.util.Arrays;
Kenny Roota02b8b02010-08-05 16:14:17 -0700137import java.util.HashMap;
San Mehat6cdd9c02010-02-09 14:45:20 -0800138import java.util.HashSet;
Kenny Root38cf8862010-09-26 14:18:51 -0700139import java.util.Iterator;
Kenny Roota02b8b02010-08-05 16:14:17 -0700140import java.util.LinkedList;
141import java.util.List;
Elliott Hughesf839b4f2014-09-26 12:30:47 -0700142import java.util.Locale;
Kenny Roota02b8b02010-08-05 16:14:17 -0700143import java.util.Map;
Kenny Root38cf8862010-09-26 14:18:51 -0700144import java.util.Map.Entry;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700145import java.util.Objects;
Daichi Hirono9fb00182016-11-08 14:12:17 +0900146import java.util.concurrent.ArrayBlockingQueue;
Svet Ganov6ee871e2015-07-10 14:29:33 -0700147import java.util.concurrent.CopyOnWriteArrayList;
Kenny Root51a573c2012-05-17 13:30:28 -0700148import java.util.concurrent.CountDownLatch;
149import java.util.concurrent.TimeUnit;
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700150import java.util.concurrent.TimeoutException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151
Kenny Root3b1abba2010-10-13 15:00:07 -0700152import javax.crypto.SecretKey;
153import javax.crypto.SecretKeyFactory;
154import javax.crypto.spec.PBEKeySpec;
155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156/**
Jeff Sharkey48877892015-03-18 11:27:19 -0700157 * Service responsible for various storage media. Connects to {@code vold} to
158 * watch for and manage dynamically added storage, such as SD cards and USB mass
159 * storage. Also decides how storage should be presented to users on the device.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 */
Sudheer Shanka2250d562016-11-07 15:41:02 -0800161class StorageManagerService extends IStorageManager.Stub
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -0700162 implements INativeDaemonConnectorCallbacks, Watchdog.Monitor {
Jason parks5af0b912010-11-29 09:05:25 -0600163
Christopher Tated417d622013-08-19 16:14:25 -0700164 // Static direct instance pointer for the tightly-coupled idle service to use
Sudheer Shanka2250d562016-11-07 15:41:02 -0800165 static StorageManagerService sSelf = null;
Christopher Tated417d622013-08-19 16:14:25 -0700166
Jeff Sharkey56e62932015-03-21 20:41:00 -0700167 public static class Lifecycle extends SystemService {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800168 private StorageManagerService mStorageManagerService;
Jeff Sharkey56e62932015-03-21 20:41:00 -0700169
170 public Lifecycle(Context context) {
171 super(context);
172 }
173
174 @Override
175 public void onStart() {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800176 mStorageManagerService = new StorageManagerService(getContext());
177 publishBinderService("mount", mStorageManagerService);
178 mStorageManagerService.start();
Jeff Sharkey56e62932015-03-21 20:41:00 -0700179 }
180
181 @Override
182 public void onBootPhase(int phase) {
183 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800184 mStorageManagerService.systemReady();
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900185 } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800186 mStorageManagerService.bootCompleted();
Jeff Sharkey56e62932015-03-21 20:41:00 -0700187 }
188 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700189
190 @Override
Jeff Sharkeyab15c392016-05-05 11:45:01 -0600191 public void onSwitchUser(int userHandle) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800192 mStorageManagerService.mCurrentUserId = userHandle;
Jeff Sharkeyab15c392016-05-05 11:45:01 -0600193 }
194
195 @Override
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700196 public void onUnlockUser(int userHandle) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800197 mStorageManagerService.onUnlockUser(userHandle);
Jeff Sharkey48877892015-03-18 11:27:19 -0700198 }
199
200 @Override
201 public void onCleanupUser(int userHandle) {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800202 mStorageManagerService.onCleanupUser(userHandle);
Jeff Sharkey48877892015-03-18 11:27:19 -0700203 }
Jeff Sharkey56e62932015-03-21 20:41:00 -0700204 }
205
Dianne Hackborn40e9f292012-11-27 19:12:23 -0800206 private static final boolean DEBUG_EVENTS = false;
Kenny Rootb7db2722011-01-25 16:39:35 -0800207 private static final boolean DEBUG_OBB = false;
Kenny Root02c87302010-07-01 08:10:18 -0700208
Kenny Root07714d42011-08-17 17:49:28 -0700209 // Disable this since it messes up long-running cryptfs operations.
210 private static final boolean WATCHDOG_ENABLE = false;
211
Jeff Sharkey00455bf2016-11-04 14:45:24 -0600212 /**
213 * Our goal is for all Android devices to be usable as development devices,
214 * which includes the new Direct Boot mode added in N. For devices that
215 * don't have native FBE support, we offer an emulation mode for developer
216 * testing purposes, but if it's prohibitively difficult to support this
217 * mode, it can be disabled for specific products using this flag.
218 */
219 private static final boolean EMULATE_FBE_SUPPORTED = true;
220
Sudheer Shanka2250d562016-11-07 15:41:02 -0800221 private static final String TAG = "StorageManagerService";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700222
Jeff Sharkey9756d752015-05-14 21:07:42 -0700223 private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700224 private static final String TAG_STORAGE_TRIM = "storage_trim";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225
Kenny Root305bcbf2010-09-03 07:56:38 -0700226 private static final String VOLD_TAG = "VoldConnector";
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700227 private static final String CRYPTD_TAG = "CryptdConnector";
Kenny Root305bcbf2010-09-03 07:56:38 -0700228
Kenny Rootcf0b38c2011-03-22 14:17:59 -0700229 /** Maximum number of ASEC containers allowed to be mounted. */
230 private static final int MAX_CONTAINERS = 250;
231
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700232 /** Magic value sent by MoveTask.cpp */
233 private static final int MOVE_STATUS_COPY_FINISHED = 82;
234
San Mehat4270e1e2010-01-29 05:32:19 -0800235 /*
236 * Internal vold response code constants
237 */
San Mehat22dd86e2010-01-12 12:21:18 -0800238 class VoldResponseCode {
San Mehat4270e1e2010-01-29 05:32:19 -0800239 /*
240 * 100 series - Requestion action was initiated; expect another reply
241 * before proceeding with a new command.
242 */
San Mehat22dd86e2010-01-12 12:21:18 -0800243 public static final int VolumeListResult = 110;
244 public static final int AsecListResult = 111;
San Mehatc1b4ce92010-02-16 17:13:03 -0800245 public static final int StorageUsersListResult = 112;
Paul Lawrencee51dcf92014-03-18 10:56:00 -0700246 public static final int CryptfsGetfieldResult = 113;
San Mehat22dd86e2010-01-12 12:21:18 -0800247
San Mehat4270e1e2010-01-29 05:32:19 -0800248 /*
249 * 200 series - Requestion action has been successfully completed.
250 */
251 public static final int ShareStatusResult = 210;
San Mehat22dd86e2010-01-12 12:21:18 -0800252 public static final int AsecPathResult = 211;
San Mehat4270e1e2010-01-29 05:32:19 -0800253 public static final int ShareEnabledResult = 212;
San Mehat22dd86e2010-01-12 12:21:18 -0800254
San Mehat4270e1e2010-01-29 05:32:19 -0800255 /*
256 * 400 series - Command was accepted, but the requested action
257 * did not take place.
258 */
259 public static final int OpFailedNoMedia = 401;
260 public static final int OpFailedMediaBlank = 402;
261 public static final int OpFailedMediaCorrupt = 403;
262 public static final int OpFailedVolNotMounted = 404;
San Mehatd9709982010-02-18 11:43:03 -0800263 public static final int OpFailedStorageBusy = 405;
San Mehat2d66cef2010-03-23 11:12:52 -0700264 public static final int OpFailedStorageNotFound = 406;
San Mehat4270e1e2010-01-29 05:32:19 -0800265
266 /*
267 * 600 series - Unsolicited broadcasts.
268 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700269 public static final int DISK_CREATED = 640;
270 public static final int DISK_SIZE_CHANGED = 641;
271 public static final int DISK_LABEL_CHANGED = 642;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700272 public static final int DISK_SCANNED = 643;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700273 public static final int DISK_SYS_PATH_CHANGED = 644;
Jeff Sharkey48877892015-03-18 11:27:19 -0700274 public static final int DISK_DESTROYED = 649;
275
276 public static final int VOLUME_CREATED = 650;
277 public static final int VOLUME_STATE_CHANGED = 651;
278 public static final int VOLUME_FS_TYPE_CHANGED = 652;
279 public static final int VOLUME_FS_UUID_CHANGED = 653;
280 public static final int VOLUME_FS_LABEL_CHANGED = 654;
281 public static final int VOLUME_PATH_CHANGED = 655;
Jeff Sharkey50a05452015-04-29 11:24:52 -0700282 public static final int VOLUME_INTERNAL_PATH_CHANGED = 656;
Jeff Sharkey48877892015-03-18 11:27:19 -0700283 public static final int VOLUME_DESTROYED = 659;
Svetoslavf23b64d2013-04-25 14:45:54 -0700284
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700285 public static final int MOVE_STATUS = 660;
Jeff Sharkey9756d752015-05-14 21:07:42 -0700286 public static final int BENCHMARK_RESULT = 661;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700287 public static final int TRIM_RESULT = 662;
San Mehat22dd86e2010-01-12 12:21:18 -0800288 }
289
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700290 private static final int VERSION_INIT = 1;
291 private static final int VERSION_ADD_PRIMARY = 2;
Jeff Sharkeyfced5342015-05-10 14:53:34 -0700292 private static final int VERSION_FIX_PRIMARY = 3;
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700293
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700294 private static final String TAG_VOLUMES = "volumes";
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700295 private static final String ATTR_VERSION = "version";
296 private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid";
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700297 private static final String ATTR_FORCE_ADOPTABLE = "forceAdoptable";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700298 private static final String TAG_VOLUME = "volume";
299 private static final String ATTR_TYPE = "type";
300 private static final String ATTR_FS_UUID = "fsUuid";
Jeff Sharkey5cc0df22015-06-17 19:44:05 -0700301 private static final String ATTR_PART_GUID = "partGuid";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700302 private static final String ATTR_NICKNAME = "nickname";
303 private static final String ATTR_USER_FLAGS = "userFlags";
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700304 private static final String ATTR_CREATED_MILLIS = "createdMillis";
305 private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis";
306 private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis";
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700307
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700308 private final AtomicFile mSettingsFile;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700309
Jeff Sharkey48877892015-03-18 11:27:19 -0700310 /**
311 * <em>Never</em> hold the lock while performing downcalls into vold, since
312 * unsolicited events can suddenly appear to update data structures.
313 */
Jeff Sharkey5f3e9342017-03-13 14:53:11 -0600314 private final Object mLock = LockGuard.installNewLock(LockGuard.INDEX_STORAGE);
Jeff Sharkey48877892015-03-18 11:27:19 -0700315
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700316 /** Set of users that we know are unlocked. */
Jeff Sharkey48877892015-03-18 11:27:19 -0700317 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700318 private int[] mLocalUnlockedUsers = EmptyArray.INT;
319 /** Set of users that system knows are unlocked. */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800320 @GuardedBy("mLock")
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700321 private int[] mSystemUnlockedUsers = EmptyArray.INT;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700322
323 /** Map from disk ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700324 @GuardedBy("mLock")
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700325 private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700326 /** Map from volume ID to disk */
Jeff Sharkey48877892015-03-18 11:27:19 -0700327 @GuardedBy("mLock")
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700328 private final ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
Jeff Sharkey48877892015-03-18 11:27:19 -0700329
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700330 /** Map from UUID to record */
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700331 @GuardedBy("mLock")
Jeff Sharkeyb36586a2015-04-27 08:42:28 -0700332 private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>();
Jeff Sharkey620b32b2015-04-23 19:36:02 -0700333 @GuardedBy("mLock")
334 private String mPrimaryStorageUuid;
Jeff Sharkey4c099d02015-05-15 13:45:00 -0700335 @GuardedBy("mLock")
336 private boolean mForceAdoptable;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -0700337
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700338 /** Map from disk ID to latches */
339 @GuardedBy("mLock")
340 private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
341
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700342 @GuardedBy("mLock")
343 private IPackageMoveObserver mMoveCallback;
344 @GuardedBy("mLock")
345 private String mMoveTargetUuid;
346
Jeff Sharkeyab15c392016-05-05 11:45:01 -0600347 private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
348
Daichi Hirono9fb00182016-11-08 14:12:17 +0900349 /** Holding lock for AppFuse business */
350 private final Object mAppFuseLock = new Object();
351
352 @GuardedBy("mAppFuseLock")
353 private int mNextAppFuseName = 0;
354
355 @GuardedBy("mAppFuseLock")
Daichi Hironoe56740d2017-02-02 13:56:45 +0900356 private AppFuseBridge mAppFuseBridge = null;
Daichi Hirono9fb00182016-11-08 14:12:17 +0900357
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700358 private VolumeInfo findVolumeByIdOrThrow(String id) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700359 synchronized (mLock) {
360 final VolumeInfo vol = mVolumes.get(id);
361 if (vol != null) {
362 return vol;
363 }
364 }
365 throw new IllegalArgumentException("No volume found for ID " + id);
366 }
367
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700368 private String findVolumeIdForPathOrThrow(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700369 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700370 for (int i = 0; i < mVolumes.size(); i++) {
371 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700372 if (vol.path != null && path.startsWith(vol.path)) {
373 return vol.id;
Jeff Sharkey48877892015-03-18 11:27:19 -0700374 }
375 }
376 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700377 throw new IllegalArgumentException("No volume found for path " + path);
Jeff Sharkey48877892015-03-18 11:27:19 -0700378 }
379
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700380 private VolumeRecord findRecordForPath(String path) {
381 synchronized (mLock) {
382 for (int i = 0; i < mVolumes.size(); i++) {
383 final VolumeInfo vol = mVolumes.valueAt(i);
384 if (vol.path != null && path.startsWith(vol.path)) {
385 return mRecords.get(vol.fsUuid);
386 }
387 }
388 }
389 return null;
390 }
391
392 private String scrubPath(String path) {
393 if (path.startsWith(Environment.getDataDirectory().getAbsolutePath())) {
394 return "internal";
395 }
396 final VolumeRecord rec = findRecordForPath(path);
397 if (rec == null || rec.createdMillis == 0) {
398 return "unknown";
399 } else {
400 return "ext:" + (int) ((System.currentTimeMillis() - rec.createdMillis)
401 / DateUtils.WEEK_IN_MILLIS) + "w";
402 }
403 }
404
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700405 private @Nullable VolumeInfo findStorageForUuid(String volumeUuid) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700406 final StorageManager storage = mContext.getSystemService(StorageManager.class);
407 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -0700408 return storage.findVolumeById(VolumeInfo.ID_EMULATED_INTERNAL);
Jeff Sharkey275e3e42015-04-24 16:10:32 -0700409 } else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
410 return storage.getPrimaryPhysicalVolume();
411 } else {
412 return storage.findEmulatedForPrivate(storage.findVolumeByUuid(volumeUuid));
413 }
414 }
415
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700416 private boolean shouldBenchmark() {
417 final long benchInterval = Settings.Global.getLong(mContext.getContentResolver(),
418 Settings.Global.STORAGE_BENCHMARK_INTERVAL, DateUtils.WEEK_IN_MILLIS);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700419 if (benchInterval == -1) {
420 return false;
421 } else if (benchInterval == 0) {
422 return true;
423 }
424
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700425 synchronized (mLock) {
426 for (int i = 0; i < mVolumes.size(); i++) {
427 final VolumeInfo vol = mVolumes.valueAt(i);
428 final VolumeRecord rec = mRecords.get(vol.fsUuid);
Jeff Sharkeye83d8a92015-09-09 14:53:38 -0700429 if (vol.isMountedWritable() && rec != null) {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700430 final long benchAge = System.currentTimeMillis() - rec.lastBenchMillis;
431 if (benchAge >= benchInterval) {
432 return true;
433 }
434 }
435 }
436 return false;
437 }
438 }
439
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700440 private CountDownLatch findOrCreateDiskScanLatch(String diskId) {
441 synchronized (mLock) {
442 CountDownLatch latch = mDiskScanLatches.get(diskId);
443 if (latch == null) {
444 latch = new CountDownLatch(1);
445 mDiskScanLatches.put(diskId, latch);
446 }
447 return latch;
448 }
449 }
450
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -0800451 private static String escapeNull(String arg) {
452 if (TextUtils.isEmpty(arg)) {
453 return "!";
454 } else {
455 if (arg.indexOf('\0') != -1 || arg.indexOf(' ') != -1) {
456 throw new IllegalArgumentException(arg);
457 }
458 return arg;
459 }
460 }
461
Paul Lawrence8e397362014-01-27 15:22:30 -0800462 /** List of crypto types.
463 * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
464 * corresponding commands in CommandListener.cpp */
465 public static final String[] CRYPTO_TYPES
466 = { "password", "default", "pattern", "pin" };
467
Brian Carlstrom7395a8a2014-04-28 22:11:01 -0700468 private final Context mContext;
Jeff Sharkeycd575992016-03-29 14:12:49 -0600469
Brian Carlstromdfad99a2014-05-07 15:21:14 -0700470 private final NativeDaemonConnector mConnector;
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700471 private final NativeDaemonConnector mCryptConnector;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700472
Jeff Sharkeycd575992016-03-29 14:12:49 -0600473 private final Thread mConnectorThread;
474 private final Thread mCryptConnectorThread;
475
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700476 private volatile boolean mSystemReady = false;
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +0900477 private volatile boolean mBootCompleted = false;
Jeff Sharkey48877892015-03-18 11:27:19 -0700478 private volatile boolean mDaemonConnected = false;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700479
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700480 private PackageManagerService mPms;
481
482 private final Callbacks mCallbacks;
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -0700483 private final LockPatternUtils mLockPatternUtils;
Jeff Sharkey48877892015-03-18 11:27:19 -0700484
Paul Lawrence1c62cbb2015-06-03 14:14:52 -0700485 // Two connectors - mConnector & mCryptConnector
486 private final CountDownLatch mConnectedSignal = new CountDownLatch(2);
Jeff Sharkey0be607c2012-11-14 14:39:19 -0800487 private final CountDownLatch mAsecsScanned = new CountDownLatch(1);
Jeff Sharkey48877892015-03-18 11:27:19 -0700488
489 private final Object mUnmountLock = new Object();
490 @GuardedBy("mUnmountLock")
491 private CountDownLatch mUnmountSignal;
Suchi Amalapurapufd3530f2010-01-18 00:15:59 -0800492
San Mehat6cdd9c02010-02-09 14:45:20 -0800493 /**
494 * Private hash of currently mounted secure containers.
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800495 * Used as a lock in methods to manipulate secure containers.
San Mehat6cdd9c02010-02-09 14:45:20 -0800496 */
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -0800497 final private HashSet<String> mAsecMountSet = new HashSet<String>();
San Mehat6cdd9c02010-02-09 14:45:20 -0800498
Kenny Root02c87302010-07-01 08:10:18 -0700499 /**
Kenny Root3b1abba2010-10-13 15:00:07 -0700500 * The size of the crypto algorithm key in bits for OBB files. Currently
501 * Twofish is used which takes 128-bit keys.
502 */
503 private static final int CRYPTO_ALGORITHM_KEY_SIZE = 128;
504
505 /**
506 * The number of times to run SHA1 in the PBKDF2 function for OBB files.
507 * 1024 is reasonably secure and not too slow.
508 */
509 private static final int PBKDF2_HASH_ROUNDS = 1024;
510
511 /**
Kenny Roota02b8b02010-08-05 16:14:17 -0700512 * Mounted OBB tracking information. Used to track the current state of all
513 * OBBs.
Kenny Root02c87302010-07-01 08:10:18 -0700514 */
Kenny Root735de3b2010-09-30 14:11:39 -0700515 final private Map<IBinder, List<ObbState>> mObbMounts = new HashMap<IBinder, List<ObbState>>();
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700516
517 /** Map from raw paths to {@link ObbState}. */
Kenny Roota02b8b02010-08-05 16:14:17 -0700518 final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>();
519
Svet Ganov6ee871e2015-07-10 14:29:33 -0700520 // Not guarded by a lock.
Sudheer Shanka2250d562016-11-07 15:41:02 -0800521 private final StorageManagerInternalImpl mStorageManagerInternal
522 = new StorageManagerInternalImpl();
Svet Ganov6ee871e2015-07-10 14:29:33 -0700523
Kenny Roota02b8b02010-08-05 16:14:17 -0700524 class ObbState implements IBinder.DeathRecipient {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700525 public ObbState(String rawPath, String canonicalPath, int callingUid,
526 IObbActionListener token, int nonce) {
527 this.rawPath = rawPath;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700528 this.canonicalPath = canonicalPath;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700529
530 this.ownerGid = UserHandle.getSharedAppGid(callingUid);
Kenny Rootaf9d6672010-10-08 09:21:39 -0700531 this.token = token;
532 this.nonce = nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700533 }
534
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700535 final String rawPath;
536 final String canonicalPath;
Kenny Roota02b8b02010-08-05 16:14:17 -0700537
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700538 final int ownerGid;
Kenny Roota02b8b02010-08-05 16:14:17 -0700539
Kenny Rootaf9d6672010-10-08 09:21:39 -0700540 // Token of remote Binder caller
541 final IObbActionListener token;
542
543 // Identifier to pass back to the token
544 final int nonce;
Kenny Roota02b8b02010-08-05 16:14:17 -0700545
Kenny Root735de3b2010-09-30 14:11:39 -0700546 public IBinder getBinder() {
547 return token.asBinder();
548 }
549
Kenny Roota02b8b02010-08-05 16:14:17 -0700550 @Override
551 public void binderDied() {
552 ObbAction action = new UnmountObbAction(this, true);
553 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root735de3b2010-09-30 14:11:39 -0700554 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700555
Kenny Root5919ac62010-10-05 09:49:40 -0700556 public void link() throws RemoteException {
557 getBinder().linkToDeath(this, 0);
558 }
559
560 public void unlink() {
Kenny Root735de3b2010-09-30 14:11:39 -0700561 getBinder().unlinkToDeath(this, 0);
Kenny Roota02b8b02010-08-05 16:14:17 -0700562 }
Kenny Root38cf8862010-09-26 14:18:51 -0700563
564 @Override
565 public String toString() {
566 StringBuilder sb = new StringBuilder("ObbState{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700567 sb.append("rawPath=").append(rawPath);
568 sb.append(",canonicalPath=").append(canonicalPath);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700569 sb.append(",ownerGid=").append(ownerGid);
570 sb.append(",token=").append(token);
571 sb.append(",binder=").append(getBinder());
Kenny Root38cf8862010-09-26 14:18:51 -0700572 sb.append('}');
573 return sb.toString();
574 }
Kenny Roota02b8b02010-08-05 16:14:17 -0700575 }
576
577 // OBB Action Handler
578 final private ObbActionHandler mObbActionHandler;
579
580 // OBB action handler messages
581 private static final int OBB_RUN_ACTION = 1;
582 private static final int OBB_MCS_BOUND = 2;
583 private static final int OBB_MCS_UNBIND = 3;
584 private static final int OBB_MCS_RECONNECT = 4;
Kenny Rootaf9d6672010-10-08 09:21:39 -0700585 private static final int OBB_FLUSH_MOUNT_STATE = 5;
Kenny Roota02b8b02010-08-05 16:14:17 -0700586
587 /*
588 * Default Container Service information
589 */
590 static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
591 "com.android.defcontainer", "com.android.defcontainer.DefaultContainerService");
592
593 final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection();
594
595 class DefaultContainerConnection implements ServiceConnection {
Jeff Sharkey48877892015-03-18 11:27:19 -0700596 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700597 public void onServiceConnected(ComponentName name, IBinder service) {
598 if (DEBUG_OBB)
599 Slog.i(TAG, "onServiceConnected");
600 IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
601 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_MCS_BOUND, imcs));
602 }
603
Jeff Sharkey48877892015-03-18 11:27:19 -0700604 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -0700605 public void onServiceDisconnected(ComponentName name) {
606 if (DEBUG_OBB)
607 Slog.i(TAG, "onServiceDisconnected");
608 }
609 };
610
611 // Used in the ObbActionHandler
612 private IMediaContainerService mContainerService = null;
Kenny Root02c87302010-07-01 08:10:18 -0700613
Christopher Tate7265abe2014-11-21 13:54:45 -0800614 // Last fstrim operation tracking
615 private static final String LAST_FSTRIM_FILE = "last-fstrim";
616 private final File mLastMaintenanceFile;
617 private long mLastMaintenance;
618
Kenny Root02c87302010-07-01 08:10:18 -0700619 // Handler messages
Jeff Sharkey48877892015-03-18 11:27:19 -0700620 private static final int H_SYSTEM_READY = 1;
621 private static final int H_DAEMON_CONNECTED = 2;
622 private static final int H_SHUTDOWN = 3;
623 private static final int H_FSTRIM = 4;
624 private static final int H_VOLUME_MOUNT = 5;
625 private static final int H_VOLUME_BROADCAST = 6;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700626 private static final int H_INTERNAL_BROADCAST = 7;
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700627 private static final int H_VOLUME_UNMOUNT = 8;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800628 private static final int H_PARTITION_FORGET = 9;
629 private static final int H_RESET = 10;
Suchi Amalapurapu6ffce2e2010-03-08 14:48:40 -0800630
Sudheer Shanka2250d562016-11-07 15:41:02 -0800631 class StorageManagerServiceHandler extends Handler {
632 public StorageManagerServiceHandler(Looper looper) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700633 super(looper);
Daniel Sandler5f27ef42010-03-16 15:42:02 -0400634 }
635
Jason parks5af0b912010-11-29 09:05:25 -0600636 @Override
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800637 public void handleMessage(Message msg) {
638 switch (msg.what) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700639 case H_SYSTEM_READY: {
Jeff Sharkey48877892015-03-18 11:27:19 -0700640 handleSystemReady();
641 break;
642 }
643 case H_DAEMON_CONNECTED: {
644 handleDaemonConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700645 break;
646 }
Christopher Tated417d622013-08-19 16:14:25 -0700647 case H_FSTRIM: {
Jeff Sharkey1783f142015-04-17 10:52:51 -0700648 if (!isReady()) {
649 Slog.i(TAG, "fstrim requested, but no daemon connection yet; trying again");
Christopher Tate7618db12015-04-28 16:32:55 -0700650 sendMessageDelayed(obtainMessage(H_FSTRIM, msg.obj),
651 DateUtils.SECOND_IN_MILLIS);
652 break;
Jeff Sharkey1783f142015-04-17 10:52:51 -0700653 }
654
Christopher Tated417d622013-08-19 16:14:25 -0700655 Slog.i(TAG, "Running fstrim idle maintenance");
Christopher Tate7265abe2014-11-21 13:54:45 -0800656
657 // Remember when we kicked it off
658 try {
659 mLastMaintenance = System.currentTimeMillis();
660 mLastMaintenanceFile.setLastModified(mLastMaintenance);
661 } catch (Exception e) {
662 Slog.e(TAG, "Unable to record last fstrim!");
663 }
664
Jeff Sharkey31d0b702016-11-21 14:16:53 -0700665 final int flags = shouldBenchmark() ? StorageManager.FSTRIM_FLAG_BENCHMARK : 0;
666 fstrim(flags);
Christopher Tate7265abe2014-11-21 13:54:45 -0800667
Christopher Tated417d622013-08-19 16:14:25 -0700668 // invoke the completion callback, if any
Jeff Sharkeye8a4b662015-06-27 15:43:45 -0700669 // TODO: fstrim is non-blocking, so remove this useless callback
Christopher Tated417d622013-08-19 16:14:25 -0700670 Runnable callback = (Runnable) msg.obj;
671 if (callback != null) {
672 callback.run();
673 }
674 break;
675 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700676 case H_SHUTDOWN: {
Sudheer Shanka2250d562016-11-07 15:41:02 -0800677 final IStorageShutdownObserver obs = (IStorageShutdownObserver) msg.obj;
Jeff Sharkey48877892015-03-18 11:27:19 -0700678 boolean success = false;
679 try {
680 success = mConnector.execute("volume", "shutdown").isClassOk();
681 } catch (NativeDaemonConnectorException ignored) {
682 }
683 if (obs != null) {
684 try {
685 obs.onShutDownComplete(success ? 0 : -1);
686 } catch (RemoteException ignored) {
687 }
688 }
689 break;
690 }
691 case H_VOLUME_MOUNT: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700692 final VolumeInfo vol = (VolumeInfo) msg.obj;
Jeff Sharkey2e606d72015-07-27 14:19:54 -0700693 if (isMountDisallowed(vol)) {
694 Slog.i(TAG, "Ignoring mount " + vol.getId() + " due to policy");
695 break;
696 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700697 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -0700698 mConnector.execute("volume", "mount", vol.id, vol.mountFlags,
699 vol.mountUserId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700700 } catch (NativeDaemonConnectorException ignored) {
701 }
702 break;
703 }
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700704 case H_VOLUME_UNMOUNT: {
705 final VolumeInfo vol = (VolumeInfo) msg.obj;
706 unmount(vol.getId());
707 break;
708 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700709 case H_VOLUME_BROADCAST: {
710 final StorageVolume userVol = (StorageVolume) msg.obj;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700711 final String envState = userVol.getState();
712 Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + envState + " to "
Jeff Sharkey48877892015-03-18 11:27:19 -0700713 + userVol.getOwner());
714
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700715 final String action = VolumeInfo.getBroadcastForEnvironment(envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700716 if (action != null) {
717 final Intent intent = new Intent(action,
718 Uri.fromFile(userVol.getPathFile()));
719 intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, userVol);
Jeff Sharkey082f83b2017-03-26 14:34:47 -0600720 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
721 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Jeff Sharkey48877892015-03-18 11:27:19 -0700722 mContext.sendBroadcastAsUser(intent, userVol.getOwner());
723 }
724 break;
725 }
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700726 case H_INTERNAL_BROADCAST: {
727 // Internal broadcasts aimed at system components, not for
728 // third-party apps.
729 final Intent intent = (Intent) msg.obj;
730 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
731 android.Manifest.permission.WRITE_MEDIA_STORAGE);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800732 break;
733 }
734 case H_PARTITION_FORGET: {
735 final String partGuid = (String) msg.obj;
736 forgetPartition(partGuid);
737 break;
738 }
739 case H_RESET: {
740 resetIfReadyAndConnected();
741 break;
Jeff Sharkeyabc3e852015-08-03 14:41:13 -0700742 }
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800743 }
744 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700745 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700746
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700747 private final Handler mHandler;
Suchi Amalapurapuc42e29e2010-02-22 16:03:53 -0800748
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700749 private BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
750 @Override
751 public void onReceive(Context context, Intent intent) {
752 final String action = intent.getAction();
753 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700754 Preconditions.checkArgument(userId >= 0);
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700755
756 try {
757 if (Intent.ACTION_USER_ADDED.equals(action)) {
758 final UserManager um = mContext.getSystemService(UserManager.class);
759 final int userSerialNumber = um.getUserSerialNumber(userId);
760 mConnector.execute("volume", "user_added", userId, userSerialNumber);
761 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700762 synchronized (mVolumes) {
763 final int size = mVolumes.size();
764 for (int i = 0; i < size; i++) {
765 final VolumeInfo vol = mVolumes.valueAt(i);
766 if (vol.mountUserId == userId) {
767 vol.mountUserId = UserHandle.USER_NULL;
768 mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
769 }
770 }
771 }
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700772 mConnector.execute("volume", "user_removed", userId);
773 }
774 } catch (NativeDaemonConnectorException e) {
775 Slog.w(TAG, "Failed to send user details to vold", e);
776 }
777 }
778 };
779
Jeff Sharkey56e62932015-03-21 20:41:00 -0700780 @Override
781 public void waitForAsecScan() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700782 waitForLatch(mAsecsScanned, "mAsecsScanned");
Kenny Root51a573c2012-05-17 13:30:28 -0700783 }
784
San Mehat207e5382010-02-04 20:46:54 -0800785 private void waitForReady() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700786 waitForLatch(mConnectedSignal, "mConnectedSignal");
Kenny Root51a573c2012-05-17 13:30:28 -0700787 }
788
Jeff Sharkey48877892015-03-18 11:27:19 -0700789 private void waitForLatch(CountDownLatch latch, String condition) {
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700790 try {
791 waitForLatch(latch, condition, -1);
792 } catch (TimeoutException ignored) {
793 }
794 }
795
796 private void waitForLatch(CountDownLatch latch, String condition, long timeoutMillis)
797 throws TimeoutException {
798 final long startMillis = SystemClock.elapsedRealtime();
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700799 while (true) {
Kenny Root51a573c2012-05-17 13:30:28 -0700800 try {
801 if (latch.await(5000, TimeUnit.MILLISECONDS)) {
San Mehat207e5382010-02-04 20:46:54 -0800802 return;
Kenny Root51a573c2012-05-17 13:30:28 -0700803 } else {
804 Slog.w(TAG, "Thread " + Thread.currentThread().getName()
Jeff Sharkey48877892015-03-18 11:27:19 -0700805 + " still waiting for " + condition + "...");
San Mehat207e5382010-02-04 20:46:54 -0800806 }
Kenny Root51a573c2012-05-17 13:30:28 -0700807 } catch (InterruptedException e) {
Jeff Sharkeyeba260d2015-04-19 14:35:16 -0700808 Slog.w(TAG, "Interrupt while waiting for " + condition);
San Mehat207e5382010-02-04 20:46:54 -0800809 }
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -0700810 if (timeoutMillis > 0 && SystemClock.elapsedRealtime() > startMillis + timeoutMillis) {
811 throw new TimeoutException("Thread " + Thread.currentThread().getName()
812 + " gave up waiting for " + condition + " after " + timeoutMillis + "ms");
813 }
San Mehat207e5382010-02-04 20:46:54 -0800814 }
San Mehat1f6301e2010-01-07 22:40:27 -0800815 }
Kenny Root02c87302010-07-01 08:10:18 -0700816
Paul Lawrence945490c2014-03-27 16:37:28 +0000817 private boolean isReady() {
818 try {
819 return mConnectedSignal.await(0, TimeUnit.MILLISECONDS);
820 } catch (InterruptedException e) {
821 return false;
822 }
823 }
824
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700825 private void handleSystemReady() {
Jeff Sharkey8924e872015-11-30 12:52:10 -0700826 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800827 resetIfReadyAndConnected();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700828
Jeff Sharkey48877892015-03-18 11:27:19 -0700829 // Start scheduling nominally-daily fstrim operations
Christopher Tate115afda2014-06-06 19:06:26 -0700830 MountServiceIdler.scheduleIdlePass(mContext);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700831 }
832
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700833 /**
834 * MediaProvider has a ton of code that makes assumptions about storage
835 * paths never changing, so we outright kill them to pick up new state.
836 */
837 @Deprecated
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700838 private void killMediaProvider(List<UserInfo> users) {
839 if (users == null) return;
840
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700841 final long token = Binder.clearCallingIdentity();
842 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700843 for (UserInfo user : users) {
844 // System user does not have media provider, so skip.
845 if (user.isSystemOnly()) continue;
846
Jeff Sharkey2a9e3f82015-12-18 10:57:58 -0700847 final ProviderInfo provider = mPms.resolveContentProvider(MediaStore.AUTHORITY,
Jeff Sharkey8a372a02016-03-16 16:25:45 -0600848 PackageManager.MATCH_DIRECT_BOOT_AWARE
849 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
850 user.id);
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700851 if (provider != null) {
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800852 final IActivityManager am = ActivityManager.getService();
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700853 try {
Jeff Sharkey85f449e2016-06-23 09:26:00 -0600854 am.killApplication(provider.applicationInfo.packageName,
855 UserHandle.getAppId(provider.applicationInfo.uid),
856 UserHandle.USER_ALL, "vold reset");
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700857 // We only need to run this once. It will kill all users' media processes.
858 break;
859 } catch (RemoteException e) {
860 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700861 }
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700862 }
Jeff Sharkeyb3cf9532015-07-17 15:12:39 -0700863 } finally {
864 Binder.restoreCallingIdentity(token);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700865 }
866 }
867
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800868 private void addInternalVolumeLocked() {
Amith Yamasania7892482015-08-07 11:09:05 -0700869 // Create a stub volume that represents internal storage
870 final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
871 VolumeInfo.TYPE_PRIVATE, null, null);
872 internal.state = VolumeInfo.STATE_MOUNTED;
873 internal.path = Environment.getDataDirectory().getAbsolutePath();
874 mVolumes.put(internal.id, internal);
875 }
876
Jeff Sharkey8924e872015-11-30 12:52:10 -0700877 private void initIfReadyAndConnected() {
878 Slog.d(TAG, "Thinking about init, mSystemReady=" + mSystemReady
879 + ", mDaemonConnected=" + mDaemonConnected);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700880 if (mSystemReady && mDaemonConnected
Paul Lawrence20be5d62016-02-26 13:51:17 -0800881 && !StorageManager.isFileEncryptedNativeOnly()) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700882 // When booting a device without native support, make sure that our
883 // user directories are locked or unlocked based on the current
884 // emulation status.
Paul Lawrence20be5d62016-02-26 13:51:17 -0800885 final boolean initLocked = StorageManager.isFileEncryptedEmulatedOnly();
Paul Crowleyd94ab732016-02-15 06:44:51 +0000886 Slog.d(TAG, "Setting up emulation state, initlocked=" + initLocked);
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700887 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Jeff Sharkey8924e872015-11-30 12:52:10 -0700888 for (UserInfo user : users) {
889 try {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700890 if (initLocked) {
891 mCryptConnector.execute("cryptfs", "lock_user_key", user.id);
892 } else {
893 mCryptConnector.execute("cryptfs", "unlock_user_key", user.id,
Paul Crowleyd94ab732016-02-15 06:44:51 +0000894 user.serialNumber, "!", "!");
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700895 }
Jeff Sharkey8924e872015-11-30 12:52:10 -0700896 } catch (NativeDaemonConnectorException e) {
897 Slog.w(TAG, "Failed to init vold", e);
898 }
899 }
900 }
901 }
902
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800903 private void resetIfReadyAndConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700904 Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
905 + ", mDaemonConnected=" + mDaemonConnected);
906 if (mSystemReady && mDaemonConnected) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800907 final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
Xiaohui Chen621b3fc2015-10-02 14:41:42 -0700908 killMediaProvider(users);
Jeff Sharkey14cbe522015-07-08 14:06:37 -0700909
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700910 final int[] systemUnlockedUsers;
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800911 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700912 systemUnlockedUsers = mSystemUnlockedUsers;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700913
Jeff Sharkey5a9bb742015-11-03 10:15:57 -0800914 mDisks.clear();
915 mVolumes.clear();
916
917 addInternalVolumeLocked();
918 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -0700919
Jeff Sharkey48877892015-03-18 11:27:19 -0700920 try {
921 mConnector.execute("volume", "reset");
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700922
923 // Tell vold about all existing and started users
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700924 for (UserInfo user : users) {
925 mConnector.execute("volume", "user_added", user.id, user.serialNumber);
926 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700927 for (int userId : systemUnlockedUsers) {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700928 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey50a05452015-04-29 11:24:52 -0700929 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700930 } catch (NativeDaemonConnectorException e) {
931 Slog.w(TAG, "Failed to reset vold", e);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700932 }
933 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700934 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700935
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700936 private void onUnlockUser(int userId) {
937 Slog.d(TAG, "onUnlockUser " + userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700938
939 // We purposefully block here to make sure that user-specific
940 // staging area is ready so it's ready for zygote-forked apps to
941 // bind mount against.
942 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700943 mConnector.execute("volume", "user_started", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700944 } catch (NativeDaemonConnectorException ignored) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700945 }
Jeff Sharkey48877892015-03-18 11:27:19 -0700946
947 // Record user as started so newly mounted volumes kick off events
948 // correctly, then synthesize events for any already-mounted volumes.
yuanhuihuiefd1f122016-07-13 21:21:03 +0800949 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700950 for (int i = 0; i < mVolumes.size(); i++) {
951 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey46349872015-07-28 10:49:47 -0700952 if (vol.isVisibleForRead(userId) && vol.isMountedReadable()) {
Svet Ganov6ee871e2015-07-10 14:29:33 -0700953 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey48877892015-03-18 11:27:19 -0700954 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -0700955
Jeff Sharkey27de30d2015-04-18 16:20:27 -0700956 final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
957 mCallbacks.notifyStorageStateChanged(userVol.getPath(), envState, envState);
Jeff Sharkey48877892015-03-18 11:27:19 -0700958 }
959 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700960 mSystemUnlockedUsers = ArrayUtils.appendInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700961 }
962 }
963
964 private void onCleanupUser(int userId) {
965 Slog.d(TAG, "onCleanupUser " + userId);
966
967 try {
Jeff Sharkeybcd262d2015-06-10 09:41:17 -0700968 mConnector.execute("volume", "user_stopped", userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700969 } catch (NativeDaemonConnectorException ignored) {
970 }
971
yuanhuihuiefd1f122016-07-13 21:21:03 +0800972 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -0700973 mSystemUnlockedUsers = ArrayUtils.removeInt(mSystemUnlockedUsers, userId);
Jeff Sharkey48877892015-03-18 11:27:19 -0700974 }
975 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700976
Christopher Tated417d622013-08-19 16:14:25 -0700977 void runIdleMaintenance(Runnable callback) {
978 mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
979 }
980
Christopher Tate7265abe2014-11-21 13:54:45 -0800981 // Binder entry point for kicking off an immediate fstrim
982 @Override
983 public void runMaintenance() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700984 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
Christopher Tate7265abe2014-11-21 13:54:45 -0800985 runIdleMaintenance(null);
986 }
987
988 @Override
989 public long lastMaintenance() {
990 return mLastMaintenance;
991 }
992
San Mehat4270e1e2010-01-29 05:32:19 -0800993 /**
San Mehat4270e1e2010-01-29 05:32:19 -0800994 * Callback from NativeDaemonConnector
995 */
Jeff Sharkey48877892015-03-18 11:27:19 -0700996 @Override
San Mehat4270e1e2010-01-29 05:32:19 -0800997 public void onDaemonConnected() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700998 mDaemonConnected = true;
999 mHandler.obtainMessage(H_DAEMON_CONNECTED).sendToTarget();
1000 }
1001
1002 private void handleDaemonConnected() {
Jeff Sharkey8924e872015-11-30 12:52:10 -07001003 initIfReadyAndConnected();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001004 resetIfReadyAndConnected();
Jeff Sharkey48877892015-03-18 11:27:19 -07001005
San Mehat4270e1e2010-01-29 05:32:19 -08001006 /*
Jeff Sharkey48877892015-03-18 11:27:19 -07001007 * Now that we've done our initialization, release
1008 * the hounds!
San Mehat4270e1e2010-01-29 05:32:19 -08001009 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001010 mConnectedSignal.countDown();
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001011 if (mConnectedSignal.getCount() != 0) {
1012 // More daemons need to connect
1013 return;
1014 }
Mike Lockwood7fa24aa2011-03-23 14:52:34 -04001015
Jeff Sharkey48877892015-03-18 11:27:19 -07001016 // On an encrypted device we can't see system properties yet, so pull
1017 // the system locale out of the mount service.
1018 if ("".equals(SystemProperties.get("vold.encrypt_progress"))) {
1019 copyLocaleFromMountService();
1020 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001021
Jeff Sharkey48877892015-03-18 11:27:19 -07001022 // Let package manager load internal ASECs.
1023 mPms.scanAvailableAsecs();
Mike Lockwood7fa24aa2011-03-23 14:52:34 -04001024
Jeff Sharkey48877892015-03-18 11:27:19 -07001025 // Notify people waiting for ASECs to be scanned that it's done.
1026 mAsecsScanned.countDown();
San Mehat4270e1e2010-01-29 05:32:19 -08001027 }
1028
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001029 private void copyLocaleFromMountService() {
1030 String systemLocale;
1031 try {
1032 systemLocale = getField(StorageManager.SYSTEM_LOCALE_KEY);
1033 } catch (RemoteException e) {
1034 return;
1035 }
1036 if (TextUtils.isEmpty(systemLocale)) {
1037 return;
1038 }
1039
1040 Slog.d(TAG, "Got locale " + systemLocale + " from mount service");
1041 Locale locale = Locale.forLanguageTag(systemLocale);
1042 Configuration config = new Configuration();
1043 config.setLocale(locale);
1044 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001045 ActivityManager.getService().updatePersistentConfiguration(config);
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001046 } catch (RemoteException e) {
1047 Slog.e(TAG, "Error setting system locale from mount service", e);
1048 }
Elliott Hughes9c33f282014-10-13 12:39:56 -07001049
1050 // Temporary workaround for http://b/17945169.
1051 Slog.d(TAG, "Setting system properties to " + systemLocale + " from mount service");
Narayan Kamathd30dbb82015-01-15 14:48:15 +00001052 SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
Elliott Hughesf839b4f2014-09-26 12:30:47 -07001053 }
1054
San Mehat4270e1e2010-01-29 05:32:19 -08001055 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001056 * Callback from NativeDaemonConnector
1057 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001058 @Override
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001059 public boolean onCheckHoldWakeLock(int code) {
1060 return false;
1061 }
1062
1063 /**
1064 * Callback from NativeDaemonConnector
1065 */
Jeff Sharkey48877892015-03-18 11:27:19 -07001066 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001067 public boolean onEvent(int code, String raw, String[] cooked) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001068 synchronized (mLock) {
1069 return onEventLocked(code, raw, cooked);
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -08001070 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001071 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001072
Jeff Sharkey48877892015-03-18 11:27:19 -07001073 private boolean onEventLocked(int code, String raw, String[] cooked) {
1074 switch (code) {
1075 case VoldResponseCode.DISK_CREATED: {
1076 if (cooked.length != 3) break;
1077 final String id = cooked[1];
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001078 int flags = Integer.parseInt(cooked[2]);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001079 if (SystemProperties.getBoolean(StorageManager.PROP_FORCE_ADOPTABLE, false)
1080 || mForceAdoptable) {
Jeff Sharkey74acbbb2015-04-21 12:14:03 -07001081 flags |= DiskInfo.FLAG_ADOPTABLE;
1082 }
Jeff Sharkey6ed74182016-08-23 13:53:53 -06001083 // Adoptable storage isn't currently supported on FBE devices
1084 if (StorageManager.isFileEncryptedNativeOnly()) {
1085 flags &= ~DiskInfo.FLAG_ADOPTABLE;
1086 }
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001087 mDisks.put(id, new DiskInfo(id, flags));
Jeff Sharkey48877892015-03-18 11:27:19 -07001088 break;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07001089 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001090 case VoldResponseCode.DISK_SIZE_CHANGED: {
1091 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001092 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001093 if (disk != null) {
1094 disk.size = Long.parseLong(cooked[2]);
San Mehat4270e1e2010-01-29 05:32:19 -08001095 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001096 break;
1097 }
1098 case VoldResponseCode.DISK_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001099 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001100 if (disk != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001101 final StringBuilder builder = new StringBuilder();
1102 for (int i = 2; i < cooked.length; i++) {
1103 builder.append(cooked[i]).append(' ');
1104 }
1105 disk.label = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001106 }
1107 break;
1108 }
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001109 case VoldResponseCode.DISK_SCANNED: {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001110 if (cooked.length != 2) break;
1111 final DiskInfo disk = mDisks.get(cooked[1]);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001112 if (disk != null) {
1113 onDiskScannedLocked(disk);
1114 }
Jeff Sharkey59d577a2015-04-11 21:27:21 -07001115 break;
1116 }
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001117 case VoldResponseCode.DISK_SYS_PATH_CHANGED: {
1118 if (cooked.length != 3) break;
1119 final DiskInfo disk = mDisks.get(cooked[1]);
1120 if (disk != null) {
1121 disk.sysPath = cooked[2];
1122 }
1123 break;
1124 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001125 case VoldResponseCode.DISK_DESTROYED: {
1126 if (cooked.length != 2) break;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07001127 final DiskInfo disk = mDisks.remove(cooked[1]);
1128 if (disk != null) {
1129 mCallbacks.notifyDiskDestroyed(disk);
1130 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001131 break;
1132 }
San Mehat4270e1e2010-01-29 05:32:19 -08001133
Jeff Sharkey48877892015-03-18 11:27:19 -07001134 case VoldResponseCode.VOLUME_CREATED: {
Jeff Sharkey48877892015-03-18 11:27:19 -07001135 final String id = cooked[1];
1136 final int type = Integer.parseInt(cooked[2]);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001137 final String diskId = TextUtils.nullIfEmpty(cooked[3]);
1138 final String partGuid = TextUtils.nullIfEmpty(cooked[4]);
1139
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001140 final DiskInfo disk = mDisks.get(diskId);
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07001141 final VolumeInfo vol = new VolumeInfo(id, type, disk, partGuid);
Jeff Sharkey48877892015-03-18 11:27:19 -07001142 mVolumes.put(id, vol);
1143 onVolumeCreatedLocked(vol);
1144 break;
1145 }
1146 case VoldResponseCode.VOLUME_STATE_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 final int oldState = vol.state;
1151 final int newState = Integer.parseInt(cooked[2]);
1152 vol.state = newState;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001153 onVolumeStateChangedLocked(vol, oldState, newState);
Jeff Sharkey48877892015-03-18 11:27:19 -07001154 }
1155 break;
1156 }
1157 case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: {
1158 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001159 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001160 if (vol != null) {
1161 vol.fsType = cooked[2];
1162 }
1163 break;
1164 }
1165 case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
1166 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001167 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001168 if (vol != null) {
1169 vol.fsUuid = cooked[2];
1170 }
1171 break;
1172 }
1173 case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001174 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001175 if (vol != null) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07001176 final StringBuilder builder = new StringBuilder();
1177 for (int i = 2; i < cooked.length; i++) {
1178 builder.append(cooked[i]).append(' ');
1179 }
1180 vol.fsLabel = builder.toString().trim();
Jeff Sharkey48877892015-03-18 11:27:19 -07001181 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001182 // TODO: notify listeners that label changed
Jeff Sharkey48877892015-03-18 11:27:19 -07001183 break;
1184 }
1185 case VoldResponseCode.VOLUME_PATH_CHANGED: {
1186 if (cooked.length != 3) break;
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001187 final VolumeInfo vol = mVolumes.get(cooked[1]);
Jeff Sharkey48877892015-03-18 11:27:19 -07001188 if (vol != null) {
1189 vol.path = cooked[2];
1190 }
1191 break;
1192 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001193 case VoldResponseCode.VOLUME_INTERNAL_PATH_CHANGED: {
1194 if (cooked.length != 3) break;
1195 final VolumeInfo vol = mVolumes.get(cooked[1]);
1196 if (vol != null) {
1197 vol.internalPath = cooked[2];
1198 }
1199 break;
1200 }
Jeff Sharkey48877892015-03-18 11:27:19 -07001201 case VoldResponseCode.VOLUME_DESTROYED: {
1202 if (cooked.length != 2) break;
1203 mVolumes.remove(cooked[1]);
1204 break;
1205 }
San Mehat4270e1e2010-01-29 05:32:19 -08001206
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001207 case VoldResponseCode.MOVE_STATUS: {
1208 final int status = Integer.parseInt(cooked[1]);
1209 onMoveStatusLocked(status);
1210 break;
1211 }
Jeff Sharkey9756d752015-05-14 21:07:42 -07001212 case VoldResponseCode.BENCHMARK_RESULT: {
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001213 if (cooked.length != 7) break;
1214 final String path = cooked[1];
1215 final String ident = cooked[2];
1216 final long create = Long.parseLong(cooked[3]);
1217 final long drop = Long.parseLong(cooked[4]);
1218 final long run = Long.parseLong(cooked[5]);
1219 final long destroy = Long.parseLong(cooked[6]);
1220
Jeff Sharkey9756d752015-05-14 21:07:42 -07001221 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001222 dropBox.addText(TAG_STORAGE_BENCHMARK, scrubPath(path)
1223 + " " + ident + " " + create + " " + run + " " + destroy);
1224
1225 final VolumeRecord rec = findRecordForPath(path);
1226 if (rec != null) {
1227 rec.lastBenchMillis = System.currentTimeMillis();
1228 writeSettingsLocked();
1229 }
1230
1231 break;
1232 }
1233 case VoldResponseCode.TRIM_RESULT: {
1234 if (cooked.length != 4) break;
1235 final String path = cooked[1];
1236 final long bytes = Long.parseLong(cooked[2]);
1237 final long time = Long.parseLong(cooked[3]);
1238
1239 final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
1240 dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path)
1241 + " " + bytes + " " + time);
1242
1243 final VolumeRecord rec = findRecordForPath(path);
1244 if (rec != null) {
1245 rec.lastTrimMillis = System.currentTimeMillis();
1246 writeSettingsLocked();
1247 }
1248
Jeff Sharkey9756d752015-05-14 21:07:42 -07001249 break;
1250 }
1251
Jeff Sharkey48877892015-03-18 11:27:19 -07001252 default: {
1253 Slog.d(TAG, "Unhandled vold event " + code);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001254 }
San Mehat4270e1e2010-01-29 05:32:19 -08001255 }
1256
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001257 return true;
San Mehat4270e1e2010-01-29 05:32:19 -08001258 }
1259
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001260 private void onDiskScannedLocked(DiskInfo disk) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001261 int volumeCount = 0;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001262 for (int i = 0; i < mVolumes.size(); i++) {
1263 final VolumeInfo vol = mVolumes.valueAt(i);
1264 if (Objects.equals(disk.id, vol.getDiskId())) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001265 volumeCount++;
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001266 }
1267 }
1268
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001269 final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
Jeff Sharkey7732e1e2016-03-30 17:14:23 -06001270 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1271 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001272 intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
1273 intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001274 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001275
1276 final CountDownLatch latch = mDiskScanLatches.remove(disk.id);
1277 if (latch != null) {
1278 latch.countDown();
1279 }
1280
Jeff Sharkeyf5a6bd72015-05-19 14:42:38 -07001281 disk.volumeCount = volumeCount;
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001282 mCallbacks.notifyDiskScanned(disk, volumeCount);
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001283 }
1284
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001285 private void onVolumeCreatedLocked(VolumeInfo vol) {
Jeff Sharkey6855c482016-03-31 14:34:38 -06001286 if (mPms.isOnlyCoreApps()) {
1287 Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId());
1288 return;
1289 }
1290
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001291 if (vol.type == VolumeInfo.TYPE_EMULATED) {
1292 final StorageManager storage = mContext.getSystemService(StorageManager.class);
1293 final VolumeInfo privateVol = storage.findPrivateForEmulated(vol);
1294
1295 if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)
1296 && VolumeInfo.ID_PRIVATE_INTERNAL.equals(privateVol.id)) {
1297 Slog.v(TAG, "Found primary storage at " + vol);
1298 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1299 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1300 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1301
1302 } else if (Objects.equals(privateVol.fsUuid, mPrimaryStorageUuid)) {
1303 Slog.v(TAG, "Found primary storage at " + vol);
1304 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1305 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1306 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1307 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001308
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001309 } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001310 // TODO: only look at first public partition
1311 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
1312 && vol.disk.isDefaultPrimary()) {
1313 Slog.v(TAG, "Found primary storage at " + vol);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001314 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_PRIMARY;
1315 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
San Mehat4270e1e2010-01-29 05:32:19 -08001316 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001317
1318 // Adoptable public disks are visible to apps, since they meet
1319 // public API requirement of being in a stable location.
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001320 if (vol.disk.isAdoptable()) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001321 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
1322 }
1323
Jeff Sharkeyab15c392016-05-05 11:45:01 -06001324 vol.mountUserId = mCurrentUserId;
Jeff Sharkey48877892015-03-18 11:27:19 -07001325 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001326
Jeff Sharkeyb2b9ab82015-04-05 21:10:42 -07001327 } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1328 mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
1329
San Mehat4270e1e2010-01-29 05:32:19 -08001330 } else {
Jeff Sharkey48877892015-03-18 11:27:19 -07001331 Slog.d(TAG, "Skipping automatic mounting of " + vol);
San Mehat4270e1e2010-01-29 05:32:19 -08001332 }
1333 }
1334
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001335 private boolean isBroadcastWorthy(VolumeInfo vol) {
1336 switch (vol.getType()) {
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001337 case VolumeInfo.TYPE_PRIVATE:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001338 case VolumeInfo.TYPE_PUBLIC:
1339 case VolumeInfo.TYPE_EMULATED:
1340 break;
1341 default:
1342 return false;
1343 }
1344
1345 switch (vol.getState()) {
1346 case VolumeInfo.STATE_MOUNTED:
1347 case VolumeInfo.STATE_MOUNTED_READ_ONLY:
1348 case VolumeInfo.STATE_EJECTING:
1349 case VolumeInfo.STATE_UNMOUNTED:
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001350 case VolumeInfo.STATE_UNMOUNTABLE:
Tony Mantlerf0d71052015-06-24 11:45:25 -07001351 case VolumeInfo.STATE_BAD_REMOVAL:
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001352 break;
1353 default:
1354 return false;
1355 }
1356
1357 return true;
1358 }
1359
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001360 private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001361 // Remember that we saw this volume so we're ready to accept user
1362 // metadata, or so we can annoy them when a private volume is ejected
1363 if (vol.isMountedReadable() && !TextUtils.isEmpty(vol.fsUuid)) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001364 VolumeRecord rec = mRecords.get(vol.fsUuid);
1365 if (rec == null) {
1366 rec = new VolumeRecord(vol.type, vol.fsUuid);
1367 rec.partGuid = vol.partGuid;
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001368 rec.createdMillis = System.currentTimeMillis();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001369 if (vol.type == VolumeInfo.TYPE_PRIVATE) {
1370 rec.nickname = vol.disk.getDescription();
1371 }
1372 mRecords.put(rec.fsUuid, rec);
1373 writeSettingsLocked();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001374 } else {
1375 // Handle upgrade case where we didn't store partition GUID
1376 if (TextUtils.isEmpty(rec.partGuid)) {
1377 rec.partGuid = vol.partGuid;
1378 writeSettingsLocked();
1379 }
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001380 }
1381 }
1382
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001383 mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
1384
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001385 // Do not broadcast before boot has completed to avoid launching the
1386 // processes that receive the intent unnecessarily.
1387 if (mBootCompleted && isBroadcastWorthy(vol)) {
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001388 final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
Jeff Sharkeyc7acac62015-06-12 16:16:56 -07001389 intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
1390 intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
Tony Mantlerf0d71052015-06-24 11:45:25 -07001391 intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
Jeff Sharkey7732e1e2016-03-30 17:14:23 -06001392 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1393 | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
Jeff Sharkeyabc3e852015-08-03 14:41:13 -07001394 mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
Jeff Sharkeye6c04f92015-04-18 21:38:05 -07001395 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001396
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001397 final String oldStateEnv = VolumeInfo.getEnvironmentForState(oldState);
1398 final String newStateEnv = VolumeInfo.getEnvironmentForState(newState);
Emily Bernier92aa5a22014-07-07 10:11:48 -04001399
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001400 if (!Objects.equals(oldStateEnv, newStateEnv)) {
1401 // Kick state changed event towards all started users. Any users
1402 // started after this point will trigger additional
1403 // user-specific broadcasts.
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07001404 for (int userId : mSystemUnlockedUsers) {
Jeff Sharkey46349872015-07-28 10:49:47 -07001405 if (vol.isVisibleForRead(userId)) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07001406 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId, false);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001407 mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
Jeff Sharkey48877892015-03-18 11:27:19 -07001408
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001409 mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
1410 newStateEnv);
San Mehat4270e1e2010-01-29 05:32:19 -08001411 }
1412 }
1413 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001414
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001415 if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.state == VolumeInfo.STATE_EJECTING) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001416 // TODO: this should eventually be handled by new ObbVolume state changes
1417 /*
1418 * Some OBBs might have been unmounted when this volume was
1419 * unmounted, so send a message to the handler to let it know to
1420 * remove those from the list of mounted OBBS.
1421 */
1422 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
1423 OBB_FLUSH_MOUNT_STATE, vol.path));
1424 }
San Mehat4270e1e2010-01-29 05:32:19 -08001425 }
1426
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001427 private void onMoveStatusLocked(int status) {
1428 if (mMoveCallback == null) {
1429 Slog.w(TAG, "Odd, status but no move requested");
1430 return;
1431 }
1432
1433 // TODO: estimate remaining time
1434 try {
Jeff Sharkey50a05452015-04-29 11:24:52 -07001435 mMoveCallback.onStatusChanged(-1, status, -1);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001436 } catch (RemoteException ignored) {
1437 }
1438
1439 // We've finished copying and we're about to clean up old data, so
1440 // remember that move was successful if we get rebooted
1441 if (status == MOVE_STATUS_COPY_FINISHED) {
1442 Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
1443
1444 mPrimaryStorageUuid = mMoveTargetUuid;
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001445 writeSettingsLocked();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001446 }
1447
1448 if (PackageManager.isMoveStatusFinished(status)) {
1449 Slog.d(TAG, "Move to " + mMoveTargetUuid + " finished with status " + status);
1450
1451 mMoveCallback = null;
1452 mMoveTargetUuid = null;
1453 }
1454 }
1455
Jeff Sharkey48877892015-03-18 11:27:19 -07001456 private void enforcePermission(String perm) {
1457 mContext.enforceCallingOrSelfPermission(perm, perm);
Mike Lockwooda5250c92011-05-23 13:44:04 -04001458 }
1459
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001460 /**
1461 * Decide if volume is mountable per device policies.
1462 */
1463 private boolean isMountDisallowed(VolumeInfo vol) {
Philip P. Moltmannec3cbb22016-09-14 13:24:52 -07001464 UserManager userManager = mContext.getSystemService(UserManager.class);
1465
1466 boolean isUsbRestricted = false;
1467 if (vol.disk != null && vol.disk.isUsb()) {
1468 isUsbRestricted = userManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER,
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001469 Binder.getCallingUserHandle());
Emily Bernier92aa5a22014-07-07 10:11:48 -04001470 }
Philip P. Moltmannec3cbb22016-09-14 13:24:52 -07001471
1472 boolean isTypeRestricted = false;
1473 if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
1474 isTypeRestricted = userManager
1475 .hasUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
1476 Binder.getCallingUserHandle());
1477 }
1478
1479 return isUsbRestricted || isTypeRestricted;
Emily Bernier92aa5a22014-07-07 10:11:48 -04001480 }
1481
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001482 private void enforceAdminUser() {
1483 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
1484 final int callingUserId = UserHandle.getCallingUserId();
1485 boolean isAdmin;
1486 long token = Binder.clearCallingIdentity();
1487 try {
1488 isAdmin = um.getUserInfo(callingUserId).isAdmin();
1489 } finally {
1490 Binder.restoreCallingIdentity(token);
1491 }
1492 if (!isAdmin) {
1493 throw new SecurityException("Only admin users can adopt sd cards");
1494 }
1495 }
1496
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001497 /**
Sudheer Shanka2250d562016-11-07 15:41:02 -08001498 * Constructs a new StorageManagerService instance
San Mehat207e5382010-02-04 20:46:54 -08001499 *
1500 * @param context Binder context for this service
1501 */
Sudheer Shanka2250d562016-11-07 15:41:02 -08001502 public StorageManagerService(Context context) {
Christopher Tated417d622013-08-19 16:14:25 -07001503 sSelf = this;
1504
San Mehat207e5382010-02-04 20:46:54 -08001505 mContext = context;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001506 mCallbacks = new Callbacks(FgThread.get().getLooper());
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07001507 mLockPatternUtils = new LockPatternUtils(mContext);
San Mehat207e5382010-02-04 20:46:54 -08001508
San Mehat207e5382010-02-04 20:46:54 -08001509 // XXX: This will go away soon in favor of IMountServiceObserver
1510 mPms = (PackageManagerService) ServiceManager.getService("package");
1511
Dianne Hackbornefa92b22013-05-03 14:11:43 -07001512 HandlerThread hthread = new HandlerThread(TAG);
1513 hthread.start();
Sudheer Shanka2250d562016-11-07 15:41:02 -08001514 mHandler = new StorageManagerServiceHandler(hthread.getLooper());
Daniel Sandler5f27ef42010-03-16 15:42:02 -04001515
Sudheer Shanka2250d562016-11-07 15:41:02 -08001516 // Add OBB Action Handler to StorageManagerService thread.
Dianne Hackborn8d044e82013-04-30 17:24:15 -07001517 mObbActionHandler = new ObbActionHandler(IoThread.get().getLooper());
Kenny Roota02b8b02010-08-05 16:14:17 -07001518
Christopher Tate7265abe2014-11-21 13:54:45 -08001519 // Initialize the last-fstrim tracking if necessary
1520 File dataDir = Environment.getDataDirectory();
1521 File systemDir = new File(dataDir, "system");
1522 mLastMaintenanceFile = new File(systemDir, LAST_FSTRIM_FILE);
1523 if (!mLastMaintenanceFile.exists()) {
1524 // Not setting mLastMaintenance here means that we will force an
1525 // fstrim during reboot following the OTA that installs this code.
1526 try {
1527 (new FileOutputStream(mLastMaintenanceFile)).close();
1528 } catch (IOException e) {
1529 Slog.e(TAG, "Unable to create fstrim record " + mLastMaintenanceFile.getPath());
1530 }
1531 } else {
1532 mLastMaintenance = mLastMaintenanceFile.lastModified();
1533 }
1534
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001535 mSettingsFile = new AtomicFile(
Jeff Sharkey8212ae02016-02-10 14:46:43 -07001536 new File(Environment.getDataSystemDirectory(), "storage.xml"));
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001537
1538 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001539 readSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001540 }
1541
Sudheer Shanka2250d562016-11-07 15:41:02 -08001542 LocalServices.addService(StorageManagerInternal.class, mStorageManagerInternal);
Svet Ganov6ee871e2015-07-10 14:29:33 -07001543
Marco Nelissenc34ebce2010-02-18 13:39:41 -08001544 /*
Kenny Root305bcbf2010-09-03 07:56:38 -07001545 * Create the connection to vold with a maximum queue of twice the
1546 * amount of containers we'd ever expect to have. This keeps an
1547 * "asec list" from blocking a thread repeatedly.
1548 */
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001549
Dianne Hackborn77b987f2014-02-26 16:20:52 -08001550 mConnector = new NativeDaemonConnector(this, "vold", MAX_CONTAINERS * 2, VOLD_TAG, 25,
1551 null);
Jeff Sharkey48877892015-03-18 11:27:19 -07001552 mConnector.setDebug(true);
Jeff Sharkey8948c012015-11-03 12:33:54 -08001553 mConnector.setWarnIfHeld(mLock);
Jeff Sharkeycd575992016-03-29 14:12:49 -06001554 mConnectorThread = new Thread(mConnector, VOLD_TAG);
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07001555
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001556 // Reuse parameters from first connector since they are tested and safe
1557 mCryptConnector = new NativeDaemonConnector(this, "cryptd",
1558 MAX_CONTAINERS * 2, CRYPTD_TAG, 25, null);
1559 mCryptConnector.setDebug(true);
Jeff Sharkeycd575992016-03-29 14:12:49 -06001560 mCryptConnectorThread = new Thread(mCryptConnector, CRYPTD_TAG);
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07001561
Jeff Sharkeybcd262d2015-06-10 09:41:17 -07001562 final IntentFilter userFilter = new IntentFilter();
1563 userFilter.addAction(Intent.ACTION_USER_ADDED);
1564 userFilter.addAction(Intent.ACTION_USER_REMOVED);
1565 mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler);
1566
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001567 synchronized (mLock) {
1568 addInternalVolumeLocked();
1569 }
Amith Yamasania7892482015-08-07 11:09:05 -07001570
Kenny Root07714d42011-08-17 17:49:28 -07001571 // Add ourself to the Watchdog monitors if enabled.
1572 if (WATCHDOG_ENABLE) {
1573 Watchdog.getInstance().addMonitor(this);
1574 }
San Mehat207e5382010-02-04 20:46:54 -08001575 }
1576
Jeff Sharkeycd575992016-03-29 14:12:49 -06001577 private void start() {
1578 mConnectorThread.start();
1579 mCryptConnectorThread.start();
1580 }
1581
Jeff Sharkey56e62932015-03-21 20:41:00 -07001582 private void systemReady() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001583 mSystemReady = true;
1584 mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
1585 }
1586
Yasuhiro Matsuda87a38b52015-07-24 22:10:16 +09001587 private void bootCompleted() {
1588 mBootCompleted = true;
1589 }
1590
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001591 private String getDefaultPrimaryStorageUuid() {
1592 if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) {
1593 return StorageManager.UUID_PRIMARY_PHYSICAL;
1594 } else {
1595 return StorageManager.UUID_PRIVATE_INTERNAL;
1596 }
1597 }
1598
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001599 private void readSettingsLocked() {
1600 mRecords.clear();
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001601 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001602 mForceAdoptable = false;
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001603
1604 FileInputStream fis = null;
1605 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001606 fis = mSettingsFile.openRead();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001607 final XmlPullParser in = Xml.newPullParser();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001608 in.setInput(fis, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001609
1610 int type;
1611 while ((type = in.next()) != END_DOCUMENT) {
1612 if (type == START_TAG) {
1613 final String tag = in.getName();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001614 if (TAG_VOLUMES.equals(tag)) {
1615 final int version = readIntAttribute(in, ATTR_VERSION, VERSION_INIT);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001616 final boolean primaryPhysical = SystemProperties.getBoolean(
1617 StorageManager.PROP_PRIMARY_PHYSICAL, false);
1618 final boolean validAttr = (version >= VERSION_FIX_PRIMARY)
1619 || (version >= VERSION_ADD_PRIMARY && !primaryPhysical);
1620 if (validAttr) {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001621 mPrimaryStorageUuid = readStringAttribute(in,
1622 ATTR_PRIMARY_STORAGE_UUID);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001623 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001624 mForceAdoptable = readBooleanAttribute(in, ATTR_FORCE_ADOPTABLE, false);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001625
1626 } else if (TAG_VOLUME.equals(tag)) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001627 final VolumeRecord rec = readVolumeRecord(in);
1628 mRecords.put(rec.fsUuid, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001629 }
1630 }
1631 }
1632 } catch (FileNotFoundException e) {
1633 // Missing metadata is okay, probably first boot
1634 } catch (IOException e) {
1635 Slog.wtf(TAG, "Failed reading metadata", e);
1636 } catch (XmlPullParserException e) {
1637 Slog.wtf(TAG, "Failed reading metadata", e);
1638 } finally {
1639 IoUtils.closeQuietly(fis);
1640 }
1641 }
1642
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001643 private void writeSettingsLocked() {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001644 FileOutputStream fos = null;
1645 try {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001646 fos = mSettingsFile.startWrite();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001647
1648 XmlSerializer out = new FastXmlSerializer();
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +01001649 out.setOutput(fos, StandardCharsets.UTF_8.name());
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001650 out.startDocument(null, true);
1651 out.startTag(null, TAG_VOLUMES);
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001652 writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
Jeff Sharkey620b32b2015-04-23 19:36:02 -07001653 writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
Jeff Sharkey4c099d02015-05-15 13:45:00 -07001654 writeBooleanAttribute(out, ATTR_FORCE_ADOPTABLE, mForceAdoptable);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001655 final int size = mRecords.size();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001656 for (int i = 0; i < size; i++) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001657 final VolumeRecord rec = mRecords.valueAt(i);
1658 writeVolumeRecord(out, rec);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001659 }
1660 out.endTag(null, TAG_VOLUMES);
1661 out.endDocument();
1662
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001663 mSettingsFile.finishWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001664 } catch (IOException e) {
1665 if (fos != null) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001666 mSettingsFile.failWrite(fos);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001667 }
1668 }
1669 }
1670
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001671 public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
1672 final int type = readIntAttribute(in, ATTR_TYPE);
1673 final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
1674 final VolumeRecord meta = new VolumeRecord(type, fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001675 meta.partGuid = readStringAttribute(in, ATTR_PART_GUID);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001676 meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
1677 meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001678 meta.createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
1679 meta.lastTrimMillis = readLongAttribute(in, ATTR_LAST_TRIM_MILLIS);
1680 meta.lastBenchMillis = readLongAttribute(in, ATTR_LAST_BENCH_MILLIS);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001681 return meta;
1682 }
1683
1684 public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
1685 out.startTag(null, TAG_VOLUME);
1686 writeIntAttribute(out, ATTR_TYPE, rec.type);
1687 writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001688 writeStringAttribute(out, ATTR_PART_GUID, rec.partGuid);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001689 writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
1690 writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07001691 writeLongAttribute(out, ATTR_CREATED_MILLIS, rec.createdMillis);
1692 writeLongAttribute(out, ATTR_LAST_TRIM_MILLIS, rec.lastTrimMillis);
1693 writeLongAttribute(out, ATTR_LAST_BENCH_MILLIS, rec.lastBenchMillis);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001694 out.endTag(null, TAG_VOLUME);
1695 }
1696
San Mehat207e5382010-02-04 20:46:54 -08001697 /**
San Mehat4270e1e2010-01-29 05:32:19 -08001698 * Exposed API calls below here
1699 */
1700
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001701 @Override
Sudheer Shanka2250d562016-11-07 15:41:02 -08001702 public void registerListener(IStorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001703 mCallbacks.register(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001704 }
1705
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001706 @Override
Sudheer Shanka2250d562016-11-07 15:41:02 -08001707 public void unregisterListener(IStorageEventListener listener) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001708 mCallbacks.unregister(listener);
San Mehat4270e1e2010-01-29 05:32:19 -08001709 }
1710
Jeff Sharkey48877892015-03-18 11:27:19 -07001711 @Override
Sudheer Shanka2250d562016-11-07 15:41:02 -08001712 public void shutdown(final IStorageShutdownObserver observer) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001713 enforcePermission(android.Manifest.permission.SHUTDOWN);
San Mehat4270e1e2010-01-29 05:32:19 -08001714
San Mehata5078592010-03-25 09:36:54 -07001715 Slog.i(TAG, "Shutting down");
Jeff Sharkey48877892015-03-18 11:27:19 -07001716 mHandler.obtainMessage(H_SHUTDOWN, observer).sendToTarget();
San Mehat4270e1e2010-01-29 05:32:19 -08001717 }
1718
Jeff Sharkey48877892015-03-18 11:27:19 -07001719 @Override
San Mehatb1043402010-02-05 08:26:50 -08001720 public boolean isUsbMassStorageConnected() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001721 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001722 }
1723
Jeff Sharkey48877892015-03-18 11:27:19 -07001724 @Override
Suchi Amalapurapu0eec21d2010-02-25 17:07:14 -08001725 public void setUsbMassStorageEnabled(boolean enable) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001726 throw new UnsupportedOperationException();
San Mehatb1043402010-02-05 08:26:50 -08001727 }
1728
Jeff Sharkey48877892015-03-18 11:27:19 -07001729 @Override
San Mehatb1043402010-02-05 08:26:50 -08001730 public boolean isUsbMassStorageEnabled() {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001731 throw new UnsupportedOperationException();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001732 }
Jason parks9ed98bc2011-01-17 09:58:35 -06001733
Jeff Sharkey48877892015-03-18 11:27:19 -07001734 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001735 public String getVolumeState(String mountPoint) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001736 throw new UnsupportedOperationException();
San Mehat7fd0fee2009-12-17 07:12:23 -08001737 }
1738
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001739 @Override
Kenny Roote1ff2142010-10-12 11:20:01 -07001740 public boolean isExternalStorageEmulated() {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07001741 throw new UnsupportedOperationException();
Kenny Roote1ff2142010-10-12 11:20:01 -07001742 }
1743
Jeff Sharkey48877892015-03-18 11:27:19 -07001744 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001745 public int mountVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001746 mount(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001747 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001748 }
1749
Jeff Sharkey48877892015-03-18 11:27:19 -07001750 @Override
Ben Komalo13c71972011-09-07 16:35:56 -07001751 public void unmountVolume(String path, boolean force, boolean removeEncryption) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001752 unmount(findVolumeIdForPathOrThrow(path));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753 }
1754
Jeff Sharkey48877892015-03-18 11:27:19 -07001755 @Override
San Mehat4270e1e2010-01-29 05:32:19 -08001756 public int formatVolume(String path) {
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001757 format(findVolumeIdForPathOrThrow(path));
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001758 return 0;
1759 }
1760
1761 @Override
1762 public void mount(String volId) {
1763 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1764 waitForReady();
1765
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001766 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey2e606d72015-07-27 14:19:54 -07001767 if (isMountDisallowed(vol)) {
1768 throw new SecurityException("Mounting " + volId + " restricted by policy");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001769 }
1770 try {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07001771 mConnector.execute("volume", "mount", vol.id, vol.mountFlags, vol.mountUserId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001772 } catch (NativeDaemonConnectorException e) {
1773 throw e.rethrowAsParcelableException();
1774 }
1775 }
1776
1777 @Override
1778 public void unmount(String volId) {
1779 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1780 waitForReady();
1781
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001782 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001783
1784 // TODO: expand PMS to know about multiple volumes
Jeff Sharkey275e3e42015-04-24 16:10:32 -07001785 if (vol.isPrimaryPhysical()) {
1786 final long ident = Binder.clearCallingIdentity();
1787 try {
1788 synchronized (mUnmountLock) {
1789 mUnmountSignal = new CountDownLatch(1);
1790 mPms.updateExternalMediaStatus(false, true);
1791 waitForLatch(mUnmountSignal, "mUnmountSignal");
1792 mUnmountSignal = null;
1793 }
1794 } finally {
1795 Binder.restoreCallingIdentity(ident);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001796 }
1797 }
1798
1799 try {
1800 mConnector.execute("volume", "unmount", vol.id);
1801 } catch (NativeDaemonConnectorException e) {
1802 throw e.rethrowAsParcelableException();
1803 }
1804 }
1805
1806 @Override
1807 public void format(String volId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001808 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
San Mehat207e5382010-02-04 20:46:54 -08001809 waitForReady();
San Mehat5b77dab2010-01-26 13:28:50 -08001810
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07001811 final VolumeInfo vol = findVolumeByIdOrThrow(volId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001812 try {
Jeff Sharkey4e83cc92015-05-27 14:38:39 -07001813 mConnector.execute("volume", "format", vol.id, "auto");
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001814 } catch (NativeDaemonConnectorException e) {
1815 throw e.rethrowAsParcelableException();
Jeff Sharkey48877892015-03-18 11:27:19 -07001816 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001817 }
1818
1819 @Override
Jeff Sharkey9756d752015-05-14 21:07:42 -07001820 public long benchmark(String volId) {
1821 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1822 waitForReady();
1823
1824 try {
Jeff Sharkey14cbe522015-07-08 14:06:37 -07001825 // TODO: make benchmark async so we don't block other commands
1826 final NativeDaemonEvent res = mConnector.execute(3 * DateUtils.MINUTE_IN_MILLIS,
1827 "volume", "benchmark", volId);
Jeff Sharkey9756d752015-05-14 21:07:42 -07001828 return Long.parseLong(res.getMessage());
Todd Kennedy8101ee62015-06-23 13:35:28 -07001829 } catch (NativeDaemonTimeoutException e) {
1830 return Long.MAX_VALUE;
Jeff Sharkey9756d752015-05-14 21:07:42 -07001831 } catch (NativeDaemonConnectorException e) {
1832 throw e.rethrowAsParcelableException();
1833 }
1834 }
1835
1836 @Override
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001837 public void partitionPublic(String diskId) {
1838 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1839 waitForReady();
1840
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001841 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001842 try {
1843 mConnector.execute("volume", "partition", diskId, "public");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001844 waitForLatch(latch, "partitionPublic", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001845 } catch (NativeDaemonConnectorException e) {
1846 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001847 } catch (TimeoutException e) {
1848 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001849 }
1850 }
1851
1852 @Override
1853 public void partitionPrivate(String diskId) {
1854 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001855 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001856 waitForReady();
1857
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001858 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001859 try {
1860 mConnector.execute("volume", "partition", diskId, "private");
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001861 waitForLatch(latch, "partitionPrivate", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001862 } catch (NativeDaemonConnectorException e) {
1863 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001864 } catch (TimeoutException e) {
1865 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001866 }
1867 }
1868
1869 @Override
1870 public void partitionMixed(String diskId, int ratio) {
1871 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
Amith Yamasani462ac3a2015-06-30 14:21:01 -07001872 enforceAdminUser();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001873 waitForReady();
1874
Jeff Sharkeyeba260d2015-04-19 14:35:16 -07001875 final CountDownLatch latch = findOrCreateDiskScanLatch(diskId);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001876 try {
1877 mConnector.execute("volume", "partition", diskId, "mixed", ratio);
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001878 waitForLatch(latch, "partitionMixed", 3 * DateUtils.MINUTE_IN_MILLIS);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001879 } catch (NativeDaemonConnectorException e) {
1880 throw e.rethrowAsParcelableException();
Jeff Sharkeyedcdaf62015-07-09 09:45:36 -07001881 } catch (TimeoutException e) {
1882 throw new IllegalStateException(e);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07001883 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001884 }
1885
Jeff Sharkey48877892015-03-18 11:27:19 -07001886 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001887 public void setVolumeNickname(String fsUuid, String nickname) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001888 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1889 waitForReady();
1890
Jeff Sharkey50a05452015-04-29 11:24:52 -07001891 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001892 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001893 final VolumeRecord rec = mRecords.get(fsUuid);
1894 rec.nickname = nickname;
Jeff Sharkey50a05452015-04-29 11:24:52 -07001895 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001896 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001897 }
1898 }
1899
1900 @Override
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001901 public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001902 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1903 waitForReady();
1904
Jeff Sharkey50a05452015-04-29 11:24:52 -07001905 Preconditions.checkNotNull(fsUuid);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001906 synchronized (mLock) {
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001907 final VolumeRecord rec = mRecords.get(fsUuid);
1908 rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001909 mCallbacks.notifyVolumeRecordChanged(rec);
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001910 writeSettingsLocked();
1911 }
1912 }
1913
1914 @Override
1915 public void forgetVolume(String fsUuid) {
1916 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1917 waitForReady();
1918
Jeff Sharkey50a05452015-04-29 11:24:52 -07001919 Preconditions.checkNotNull(fsUuid);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001920
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001921 synchronized (mLock) {
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001922 final VolumeRecord rec = mRecords.remove(fsUuid);
1923 if (rec != null && !TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001924 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001925 }
1926 mCallbacks.notifyVolumeForgotten(fsUuid);
Jeff Sharkey50a05452015-04-29 11:24:52 -07001927
1928 // If this had been primary storage, revert back to internal and
1929 // reset vold so we bind into new volume into place.
1930 if (Objects.equals(mPrimaryStorageUuid, fsUuid)) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001931 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001932 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001933 }
1934
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07001935 writeSettingsLocked();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07001936 }
1937 }
1938
Jeff Sharkey7d2af542015-05-12 15:27:15 -07001939 @Override
1940 public void forgetAllVolumes() {
1941 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
1942 waitForReady();
1943
Jeff Sharkey50a05452015-04-29 11:24:52 -07001944 synchronized (mLock) {
1945 for (int i = 0; i < mRecords.size(); i++) {
1946 final String fsUuid = mRecords.keyAt(i);
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001947 final VolumeRecord rec = mRecords.valueAt(i);
1948 if (!TextUtils.isEmpty(rec.partGuid)) {
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001949 mHandler.obtainMessage(H_PARTITION_FORGET, rec.partGuid).sendToTarget();
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001950 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001951 mCallbacks.notifyVolumeForgotten(fsUuid);
1952 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07001953 mRecords.clear();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001954
Jeff Sharkeyfced5342015-05-10 14:53:34 -07001955 if (!Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, mPrimaryStorageUuid)) {
1956 mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
1957 }
1958
1959 writeSettingsLocked();
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08001960 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkey50a05452015-04-29 11:24:52 -07001961 }
1962 }
1963
Jeff Sharkey5cc0df22015-06-17 19:44:05 -07001964 private void forgetPartition(String partGuid) {
1965 try {
1966 mConnector.execute("volume", "forget_partition", partGuid);
1967 } catch (NativeDaemonConnectorException e) {
1968 Slog.w(TAG, "Failed to forget key for " + partGuid + ": " + e);
1969 }
1970 }
1971
Jeff Sharkey31d0b702016-11-21 14:16:53 -07001972 @Override
1973 public void fstrim(int flags) {
1974 enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
1975 waitForReady();
1976
1977 String cmd;
1978 if ((flags & StorageManager.FSTRIM_FLAG_DEEP) != 0) {
1979 cmd = "dodtrim";
1980 } else {
1981 cmd = "dotrim";
1982 }
1983 if ((flags & StorageManager.FSTRIM_FLAG_BENCHMARK) != 0) {
1984 cmd += "bench";
1985 }
1986
1987 try {
1988 mConnector.execute("fstrim", cmd);
1989 } catch (NativeDaemonConnectorException e) {
1990 Slog.e(TAG, "Failed to run fstrim: " + e);
1991 }
1992 }
1993
Svet Ganov6ee871e2015-07-10 14:29:33 -07001994 private void remountUidExternalStorage(int uid, int mode) {
Jeff Sharkey9527b222015-06-24 15:24:48 -07001995 waitForReady();
1996
Svet Ganov6ee871e2015-07-10 14:29:33 -07001997 String modeName = "none";
1998 switch (mode) {
1999 case Zygote.MOUNT_EXTERNAL_DEFAULT: {
2000 modeName = "default";
2001 } break;
2002
2003 case Zygote.MOUNT_EXTERNAL_READ: {
2004 modeName = "read";
2005 } break;
2006
2007 case Zygote.MOUNT_EXTERNAL_WRITE: {
2008 modeName = "write";
2009 } break;
Jeff Sharkey9527b222015-06-24 15:24:48 -07002010 }
2011
2012 try {
Svet Ganov6ee871e2015-07-10 14:29:33 -07002013 mConnector.execute("volume", "remount_uid", uid, modeName);
Jeff Sharkey9527b222015-06-24 15:24:48 -07002014 } catch (NativeDaemonConnectorException e) {
Svet Ganov6ee871e2015-07-10 14:29:33 -07002015 Slog.w(TAG, "Failed to remount UID " + uid + " as " + modeName + ": " + e);
Jeff Sharkey9527b222015-06-24 15:24:48 -07002016 }
2017 }
2018
2019 @Override
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002020 public void setDebugFlags(int flags, int mask) {
2021 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2022 waitForReady();
2023
Jeff Sharkeyba512352015-11-12 20:17:45 -08002024 if ((mask & StorageManager.DEBUG_EMULATE_FBE) != 0) {
Jeff Sharkey00455bf2016-11-04 14:45:24 -06002025 if (!EMULATE_FBE_SUPPORTED) {
2026 throw new IllegalStateException(
2027 "Emulation not supported on this device");
2028 }
Paul Lawrence20be5d62016-02-26 13:51:17 -08002029 if (StorageManager.isFileEncryptedNativeOnly()) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002030 throw new IllegalStateException(
Jeff Sharkey00455bf2016-11-04 14:45:24 -06002031 "Emulation not supported on device with native FBE");
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002032 }
Jeff Sharkey5a785162016-03-21 13:02:06 -06002033 if (mLockPatternUtils.isCredentialRequiredToDecrypt(false)) {
2034 throw new IllegalStateException(
2035 "Emulation requires disabling 'Secure start-up' in Settings > Security");
2036 }
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002037
Jeff Sharkey1176e512016-02-29 17:01:26 -07002038 final long token = Binder.clearCallingIdentity();
2039 try {
2040 final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
2041 SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002042
Jeff Sharkey1176e512016-02-29 17:01:26 -07002043 // Perform hard reboot to kick policy into place
2044 mContext.getSystemService(PowerManager.class).reboot(null);
2045 } finally {
2046 Binder.restoreCallingIdentity(token);
2047 }
Jeff Sharkeyba512352015-11-12 20:17:45 -08002048 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002049
Jeff Sharkeyba512352015-11-12 20:17:45 -08002050 if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
Jeff Sharkey6ed74182016-08-23 13:53:53 -06002051 if (StorageManager.isFileEncryptedNativeOnly()) {
2052 throw new IllegalStateException(
2053 "Adoptable storage not available on device with native FBE");
2054 }
2055
Jeff Sharkeyba512352015-11-12 20:17:45 -08002056 synchronized (mLock) {
2057 mForceAdoptable = (flags & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0;
2058
2059 writeSettingsLocked();
2060 mHandler.obtainMessage(H_RESET).sendToTarget();
2061 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002062 }
Jeff Sharkey33dd1562016-04-07 11:05:33 -06002063
2064 if ((mask & (StorageManager.DEBUG_SDCARDFS_FORCE_ON
2065 | StorageManager.DEBUG_SDCARDFS_FORCE_OFF)) != 0) {
2066 final String value;
2067 if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_ON) != 0) {
2068 value = "force_on";
2069 } else if ((flags & StorageManager.DEBUG_SDCARDFS_FORCE_OFF) != 0) {
2070 value = "force_off";
2071 } else {
2072 value = "";
2073 }
2074
2075 final long token = Binder.clearCallingIdentity();
2076 try {
2077 SystemProperties.set(StorageManager.PROP_SDCARDFS, value);
2078
2079 // Reset storage to kick new setting into place
2080 mHandler.obtainMessage(H_RESET).sendToTarget();
2081 } finally {
2082 Binder.restoreCallingIdentity(token);
2083 }
2084 }
Jeff Sharkeye53e2d92017-03-25 23:14:06 -06002085
2086 if ((mask & StorageManager.DEBUG_VIRTUAL_DISK) != 0) {
2087 final boolean enabled = (flags & StorageManager.DEBUG_VIRTUAL_DISK) != 0;
2088
2089 final long token = Binder.clearCallingIdentity();
2090 try {
2091 SystemProperties.set(StorageManager.PROP_VIRTUAL_DISK, Boolean.toString(enabled));
2092
2093 // Reset storage to kick new setting into place
2094 mHandler.obtainMessage(H_RESET).sendToTarget();
2095 } finally {
2096 Binder.restoreCallingIdentity(token);
2097 }
2098 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07002099 }
2100
2101 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002102 public String getPrimaryStorageUuid() {
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002103 synchronized (mLock) {
2104 return mPrimaryStorageUuid;
2105 }
2106 }
2107
2108 @Override
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002109 public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback) {
2110 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
2111 waitForReady();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002112
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002113 final VolumeInfo from;
2114 final VolumeInfo to;
2115
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002116 synchronized (mLock) {
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002117 if (Objects.equals(mPrimaryStorageUuid, volumeUuid)) {
2118 throw new IllegalArgumentException("Primary storage already at " + volumeUuid);
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002119 }
2120
2121 if (mMoveCallback != null) {
2122 throw new IllegalStateException("Move already in progress");
2123 }
2124 mMoveCallback = callback;
2125 mMoveTargetUuid = volumeUuid;
2126
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002127 // When moving to/from primary physical volume, we probably just nuked
2128 // the current storage location, so we have nothing to move.
2129 if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid)
2130 || Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
2131 Slog.d(TAG, "Skipping move to/from primary physical");
2132 onMoveStatusLocked(MOVE_STATUS_COPY_FINISHED);
2133 onMoveStatusLocked(PackageManager.MOVE_SUCCEEDED);
Jeff Sharkey5a9bb742015-11-03 10:15:57 -08002134 mHandler.obtainMessage(H_RESET).sendToTarget();
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002135 return;
Jeff Sharkeyfced5342015-05-10 14:53:34 -07002136
2137 } else {
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002138 from = findStorageForUuid(mPrimaryStorageUuid);
2139 to = findStorageForUuid(volumeUuid);
Jeff Sharkeyef10ee02015-07-05 14:17:27 -07002140
2141 if (from == null) {
2142 Slog.w(TAG, "Failing move due to missing from volume " + mPrimaryStorageUuid);
2143 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2144 return;
2145 } else if (to == null) {
2146 Slog.w(TAG, "Failing move due to missing to volume " + volumeUuid);
2147 onMoveStatusLocked(PackageManager.MOVE_FAILED_INTERNAL_ERROR);
2148 return;
2149 }
Jeff Sharkey275e3e42015-04-24 16:10:32 -07002150 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002151 }
Jeff Sharkeya31460c2016-06-22 09:04:33 -06002152
2153 try {
2154 mConnector.execute("volume", "move_storage", from.id, to.id);
2155 } catch (NativeDaemonConnectorException e) {
2156 throw e.rethrowAsParcelableException();
2157 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07002158 }
2159
2160 @Override
Mike Lockwoodecedfdc2011-06-08 15:11:59 -07002161 public int[] getStorageUsers(String path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002162 enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
San Mehatc1b4ce92010-02-16 17:13:03 -08002163 waitForReady();
2164 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002165 final String[] r = NativeDaemonEvent.filterMessageList(
2166 mConnector.executeForList("storage", "users", path),
2167 VoldResponseCode.StorageUsersListResult);
2168
San Mehatc1b4ce92010-02-16 17:13:03 -08002169 // FMT: <pid> <process name>
2170 int[] data = new int[r.length];
2171 for (int i = 0; i < r.length; i++) {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002172 String[] tok = r[i].split(" ");
San Mehatc1b4ce92010-02-16 17:13:03 -08002173 try {
2174 data[i] = Integer.parseInt(tok[0]);
2175 } catch (NumberFormatException nfe) {
San Mehata5078592010-03-25 09:36:54 -07002176 Slog.e(TAG, String.format("Error parsing pid %s", tok[0]));
San Mehatc1b4ce92010-02-16 17:13:03 -08002177 return new int[0];
2178 }
2179 }
2180 return data;
2181 } catch (NativeDaemonConnectorException e) {
San Mehata5078592010-03-25 09:36:54 -07002182 Slog.e(TAG, "Failed to retrieve storage users list", e);
San Mehatc1b4ce92010-02-16 17:13:03 -08002183 return new int[0];
2184 }
2185 }
2186
San Mehatb1043402010-02-05 08:26:50 -08002187 private void warnOnNotMounted() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002188 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07002189 for (int i = 0; i < mVolumes.size(); i++) {
2190 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07002191 if (vol.isPrimary() && vol.isMountedWritable()) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002192 // Cool beans, we have a mounted primary volume
2193 return;
2194 }
Jeff Sharkey32ee8312012-09-30 13:21:31 -07002195 }
San Mehatb1043402010-02-05 08:26:50 -08002196 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002197
2198 Slog.w(TAG, "No primary storage mounted!");
San Mehatb1043402010-02-05 08:26:50 -08002199 }
2200
San Mehat4270e1e2010-01-29 05:32:19 -08002201 public String[] getSecureContainerList() {
Jeff Sharkey48877892015-03-18 11:27:19 -07002202 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002203 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002204 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002205
San Mehat4270e1e2010-01-29 05:32:19 -08002206 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002207 return NativeDaemonEvent.filterMessageList(
2208 mConnector.executeForList("asec", "list"), VoldResponseCode.AsecListResult);
San Mehat4270e1e2010-01-29 05:32:19 -08002209 } catch (NativeDaemonConnectorException e) {
2210 return new String[0];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002211 }
2212 }
San Mehat36972292010-01-06 11:06:32 -08002213
Kenny Root6dceb882012-04-12 14:23:49 -07002214 public int createSecureContainer(String id, int sizeMb, String fstype, String key,
2215 int ownerUid, boolean external) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002216 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehat207e5382010-02-04 20:46:54 -08002217 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002218 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002219
San Mehatb1043402010-02-05 08:26:50 -08002220 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002221 try {
Jeff Sharkey56cd6462013-06-07 15:09:15 -07002222 mConnector.execute("asec", "create", id, sizeMb, fstype, new SensitiveArg(key),
2223 ownerUid, external ? "1" : "0");
San Mehat4270e1e2010-01-29 05:32:19 -08002224 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002225 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002226 }
San Mehata181b212010-02-11 06:50:20 -08002227
2228 if (rc == StorageResultCode.OperationSucceeded) {
2229 synchronized (mAsecMountSet) {
2230 mAsecMountSet.add(id);
2231 }
2232 }
San Mehat4270e1e2010-01-29 05:32:19 -08002233 return rc;
San Mehat36972292010-01-06 11:06:32 -08002234 }
2235
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002236 @Override
2237 public int resizeSecureContainer(String id, int sizeMb, String key) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002238 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002239 waitForReady();
2240 warnOnNotMounted();
2241
2242 int rc = StorageResultCode.OperationSucceeded;
2243 try {
2244 mConnector.execute("asec", "resize", id, sizeMb, new SensitiveArg(key));
2245 } catch (NativeDaemonConnectorException e) {
2246 rc = StorageResultCode.OperationFailedInternalError;
2247 }
2248 return rc;
2249 }
2250
San Mehat4270e1e2010-01-29 05:32:19 -08002251 public int finalizeSecureContainer(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002252 enforcePermission(android.Manifest.permission.ASEC_CREATE);
San Mehatb1043402010-02-05 08:26:50 -08002253 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002254
San Mehatb1043402010-02-05 08:26:50 -08002255 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002256 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002257 mConnector.execute("asec", "finalize", id);
San Mehata181b212010-02-11 06:50:20 -08002258 /*
2259 * Finalization does a remount, so no need
2260 * to update mAsecMountSet
2261 */
San Mehat4270e1e2010-01-29 05:32:19 -08002262 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002263 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002264 }
San Mehat4270e1e2010-01-29 05:32:19 -08002265 return rc;
San Mehat36972292010-01-06 11:06:32 -08002266 }
2267
Kenny Root6dceb882012-04-12 14:23:49 -07002268 public int fixPermissionsSecureContainer(String id, int gid, String filename) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002269 enforcePermission(android.Manifest.permission.ASEC_CREATE);
Kenny Root6dceb882012-04-12 14:23:49 -07002270 warnOnNotMounted();
2271
2272 int rc = StorageResultCode.OperationSucceeded;
2273 try {
2274 mConnector.execute("asec", "fixperms", id, gid, filename);
2275 /*
2276 * Fix permissions does a remount, so no need to update
2277 * mAsecMountSet
2278 */
2279 } catch (NativeDaemonConnectorException e) {
2280 rc = StorageResultCode.OperationFailedInternalError;
2281 }
2282 return rc;
2283 }
2284
San Mehatd9709982010-02-18 11:43:03 -08002285 public int destroySecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002286 enforcePermission(android.Manifest.permission.ASEC_DESTROY);
San Mehat207e5382010-02-04 20:46:54 -08002287 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002288 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002289
Kenny Rootaa485402010-09-14 14:49:41 -07002290 /*
2291 * Force a GC to make sure AssetManagers in other threads of the
2292 * system_server are cleaned up. We have to do this since AssetManager
2293 * instances are kept as a WeakReference and it's possible we have files
2294 * open on the external storage.
2295 */
2296 Runtime.getRuntime().gc();
2297
San Mehatb1043402010-02-05 08:26:50 -08002298 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002299 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002300 final Command cmd = new Command("asec", "destroy", id);
2301 if (force) {
2302 cmd.appendArg("force");
2303 }
2304 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002305 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002306 int code = e.getCode();
2307 if (code == VoldResponseCode.OpFailedStorageBusy) {
2308 rc = StorageResultCode.OperationFailedStorageBusy;
2309 } else {
2310 rc = StorageResultCode.OperationFailedInternalError;
2311 }
San Mehat02735bc2010-01-26 15:18:08 -08002312 }
San Mehata181b212010-02-11 06:50:20 -08002313
2314 if (rc == StorageResultCode.OperationSucceeded) {
2315 synchronized (mAsecMountSet) {
2316 if (mAsecMountSet.contains(id)) {
2317 mAsecMountSet.remove(id);
2318 }
2319 }
2320 }
2321
San Mehat4270e1e2010-01-29 05:32:19 -08002322 return rc;
San Mehat36972292010-01-06 11:06:32 -08002323 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002324
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002325 public int mountSecureContainer(String id, String key, int ownerUid, boolean readOnly) {
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 Mehata181b212010-02-11 06:50:20 -08002330 synchronized (mAsecMountSet) {
2331 if (mAsecMountSet.contains(id)) {
2332 return StorageResultCode.OperationFailedStorageMounted;
2333 }
2334 }
2335
San Mehatb1043402010-02-05 08:26:50 -08002336 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002337 try {
Jeff Sharkey941a8ba2014-08-20 16:26:32 -07002338 mConnector.execute("asec", "mount", id, new SensitiveArg(key), ownerUid,
2339 readOnly ? "ro" : "rw");
San Mehat4270e1e2010-01-29 05:32:19 -08002340 } catch (NativeDaemonConnectorException e) {
Kenny Rootf0304622010-03-19 19:20:42 -07002341 int code = e.getCode();
2342 if (code != VoldResponseCode.OpFailedStorageBusy) {
2343 rc = StorageResultCode.OperationFailedInternalError;
2344 }
San Mehat02735bc2010-01-26 15:18:08 -08002345 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002346
2347 if (rc == StorageResultCode.OperationSucceeded) {
2348 synchronized (mAsecMountSet) {
2349 mAsecMountSet.add(id);
2350 }
2351 }
San Mehat4270e1e2010-01-29 05:32:19 -08002352 return rc;
San Mehat36972292010-01-06 11:06:32 -08002353 }
2354
San Mehatd9709982010-02-18 11:43:03 -08002355 public int unmountSecureContainer(String id, boolean force) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002356 enforcePermission(android.Manifest.permission.ASEC_MOUNT_UNMOUNT);
San Mehat207e5382010-02-04 20:46:54 -08002357 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002358 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002359
San Mehat6cdd9c02010-02-09 14:45:20 -08002360 synchronized (mAsecMountSet) {
2361 if (!mAsecMountSet.contains(id)) {
San Mehata181b212010-02-11 06:50:20 -08002362 return StorageResultCode.OperationFailedStorageNotMounted;
San Mehat6cdd9c02010-02-09 14:45:20 -08002363 }
2364 }
2365
Kenny Rootaa485402010-09-14 14:49:41 -07002366 /*
2367 * Force a GC to make sure AssetManagers in other threads of the
2368 * system_server are cleaned up. We have to do this since AssetManager
2369 * instances are kept as a WeakReference and it's possible we have files
2370 * open on the external storage.
2371 */
2372 Runtime.getRuntime().gc();
2373
San Mehatb1043402010-02-05 08:26:50 -08002374 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002375 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002376 final Command cmd = new Command("asec", "unmount", id);
2377 if (force) {
2378 cmd.appendArg("force");
2379 }
2380 mConnector.execute(cmd);
San Mehat4270e1e2010-01-29 05:32:19 -08002381 } catch (NativeDaemonConnectorException e) {
San Mehatd9709982010-02-18 11:43:03 -08002382 int code = e.getCode();
2383 if (code == VoldResponseCode.OpFailedStorageBusy) {
2384 rc = StorageResultCode.OperationFailedStorageBusy;
2385 } else {
2386 rc = StorageResultCode.OperationFailedInternalError;
2387 }
San Mehat02735bc2010-01-26 15:18:08 -08002388 }
San Mehat6cdd9c02010-02-09 14:45:20 -08002389
2390 if (rc == StorageResultCode.OperationSucceeded) {
2391 synchronized (mAsecMountSet) {
2392 mAsecMountSet.remove(id);
2393 }
2394 }
San Mehat4270e1e2010-01-29 05:32:19 -08002395 return rc;
San Mehat9dba7092010-01-18 06:47:41 -08002396 }
2397
San Mehat6cdd9c02010-02-09 14:45:20 -08002398 public boolean isSecureContainerMounted(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002399 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat6cdd9c02010-02-09 14:45:20 -08002400 waitForReady();
2401 warnOnNotMounted();
2402
2403 synchronized (mAsecMountSet) {
2404 return mAsecMountSet.contains(id);
2405 }
2406 }
2407
San Mehat4270e1e2010-01-29 05:32:19 -08002408 public int renameSecureContainer(String oldId, String newId) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002409 enforcePermission(android.Manifest.permission.ASEC_RENAME);
San Mehat207e5382010-02-04 20:46:54 -08002410 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002411 warnOnNotMounted();
San Mehat4270e1e2010-01-29 05:32:19 -08002412
San Mehata181b212010-02-11 06:50:20 -08002413 synchronized (mAsecMountSet) {
San Mehat85451ee2010-02-24 08:54:18 -08002414 /*
Jason parks9ed98bc2011-01-17 09:58:35 -06002415 * Because a mounted container has active internal state which cannot be
San Mehat85451ee2010-02-24 08:54:18 -08002416 * changed while active, we must ensure both ids are not currently mounted.
2417 */
2418 if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
San Mehata181b212010-02-11 06:50:20 -08002419 return StorageResultCode.OperationFailedStorageMounted;
2420 }
2421 }
2422
San Mehatb1043402010-02-05 08:26:50 -08002423 int rc = StorageResultCode.OperationSucceeded;
San Mehat4270e1e2010-01-29 05:32:19 -08002424 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002425 mConnector.execute("asec", "rename", oldId, newId);
San Mehat4270e1e2010-01-29 05:32:19 -08002426 } catch (NativeDaemonConnectorException e) {
San Mehatb1043402010-02-05 08:26:50 -08002427 rc = StorageResultCode.OperationFailedInternalError;
San Mehat02735bc2010-01-26 15:18:08 -08002428 }
San Mehata181b212010-02-11 06:50:20 -08002429
San Mehat4270e1e2010-01-29 05:32:19 -08002430 return rc;
San Mehat45f61042010-01-23 08:12:43 -08002431 }
2432
San Mehat4270e1e2010-01-29 05:32:19 -08002433 public String getSecureContainerPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002434 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
San Mehat207e5382010-02-04 20:46:54 -08002435 waitForReady();
San Mehatb1043402010-02-05 08:26:50 -08002436 warnOnNotMounted();
San Mehatf919cd022010-02-04 15:10:38 -08002437
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002438 final NativeDaemonEvent event;
San Mehat2d66cef2010-03-23 11:12:52 -07002439 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002440 event = mConnector.execute("asec", "path", id);
2441 event.checkCode(VoldResponseCode.AsecPathResult);
2442 return event.getMessage();
San Mehat2d66cef2010-03-23 11:12:52 -07002443 } catch (NativeDaemonConnectorException e) {
2444 int code = e.getCode();
2445 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Fredrik Helmera20c8ef2011-02-09 16:16:10 +01002446 Slog.i(TAG, String.format("Container '%s' not found", id));
2447 return null;
San Mehat22dd86e2010-01-12 12:21:18 -08002448 } else {
San Mehat2d66cef2010-03-23 11:12:52 -07002449 throw new IllegalStateException(String.format("Unexpected response code %d", code));
San Mehat22dd86e2010-01-12 12:21:18 -08002450 }
2451 }
San Mehat22dd86e2010-01-12 12:21:18 -08002452 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002453
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002454 public String getSecureContainerFilesystemPath(String id) {
Jeff Sharkey48877892015-03-18 11:27:19 -07002455 enforcePermission(android.Manifest.permission.ASEC_ACCESS);
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002456 waitForReady();
2457 warnOnNotMounted();
2458
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002459 final NativeDaemonEvent event;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002460 try {
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002461 event = mConnector.execute("asec", "fspath", id);
2462 event.checkCode(VoldResponseCode.AsecPathResult);
2463 return event.getMessage();
Dianne Hackborn292f8bc2011-06-27 16:27:41 -07002464 } catch (NativeDaemonConnectorException e) {
2465 int code = e.getCode();
2466 if (code == VoldResponseCode.OpFailedStorageNotFound) {
2467 Slog.i(TAG, String.format("Container '%s' not found", id));
2468 return null;
2469 } else {
2470 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2471 }
2472 }
2473 }
2474
Jeff Sharkey48877892015-03-18 11:27:19 -07002475 @Override
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002476 public void finishMediaUpdate() {
Jeff Sharkey9527b222015-06-24 15:24:48 -07002477 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
Rubin Xucd7a0142015-04-17 23:45:27 +01002478 throw new SecurityException("no permission to call finishMediaUpdate()");
2479 }
Jeff Sharkey48877892015-03-18 11:27:19 -07002480 if (mUnmountSignal != null) {
2481 mUnmountSignal.countDown();
2482 } else {
2483 Slog.w(TAG, "Odd, nobody asked to unmount?");
2484 }
Suchi Amalapurapue99bb5f2010-03-19 14:36:49 -07002485 }
Kenny Root02c87302010-07-01 08:10:18 -07002486
Kenny Roota02b8b02010-08-05 16:14:17 -07002487 private boolean isUidOwnerOfPackageOrSystem(String packageName, int callerUid) {
2488 if (callerUid == android.os.Process.SYSTEM_UID) {
2489 return true;
2490 }
2491
Kenny Root02c87302010-07-01 08:10:18 -07002492 if (packageName == null) {
2493 return false;
2494 }
2495
Jeff Sharkeycd654482016-01-08 17:42:11 -07002496 final int packageUid = mPms.getPackageUid(packageName,
2497 PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(callerUid));
Kenny Root02c87302010-07-01 08:10:18 -07002498
2499 if (DEBUG_OBB) {
2500 Slog.d(TAG, "packageName = " + packageName + ", packageUid = " +
2501 packageUid + ", callerUid = " + callerUid);
2502 }
2503
2504 return callerUid == packageUid;
2505 }
2506
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002507 public String getMountedObbPath(String rawPath) {
2508 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002509
Kenny Root02c87302010-07-01 08:10:18 -07002510 waitForReady();
2511 warnOnNotMounted();
2512
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002513 final ObbState state;
Rubin Xucd7a0142015-04-17 23:45:27 +01002514 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002515 state = mObbPathToStateMap.get(rawPath);
2516 }
2517 if (state == null) {
2518 Slog.w(TAG, "Failed to find OBB mounted at " + rawPath);
2519 return null;
2520 }
2521
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002522 final NativeDaemonEvent event;
Kenny Root02c87302010-07-01 08:10:18 -07002523 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07002524 event = mConnector.execute("obb", "path", state.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002525 event.checkCode(VoldResponseCode.AsecPathResult);
2526 return event.getMessage();
Kenny Root02c87302010-07-01 08:10:18 -07002527 } catch (NativeDaemonConnectorException e) {
2528 int code = e.getCode();
2529 if (code == VoldResponseCode.OpFailedStorageNotFound) {
Kenny Roota02b8b02010-08-05 16:14:17 -07002530 return null;
Kenny Root02c87302010-07-01 08:10:18 -07002531 } else {
2532 throw new IllegalStateException(String.format("Unexpected response code %d", code));
2533 }
2534 }
2535 }
2536
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002537 @Override
2538 public boolean isObbMounted(String rawPath) {
2539 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002540 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002541 return mObbPathToStateMap.containsKey(rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07002542 }
Kenny Root02c87302010-07-01 08:10:18 -07002543 }
2544
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002545 @Override
2546 public void mountObb(
2547 String rawPath, String canonicalPath, String key, IObbActionListener token, int nonce) {
2548 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2549 Preconditions.checkNotNull(canonicalPath, "canonicalPath cannot be null");
2550 Preconditions.checkNotNull(token, "token cannot be null");
Kenny Rootaf9d6672010-10-08 09:21:39 -07002551
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002552 final int callingUid = Binder.getCallingUid();
2553 final ObbState obbState = new ObbState(rawPath, canonicalPath, callingUid, token, nonce);
2554 final ObbAction action = new MountObbAction(obbState, key, callingUid);
Kenny Roota02b8b02010-08-05 16:14:17 -07002555 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
2556
2557 if (DEBUG_OBB)
2558 Slog.i(TAG, "Send to OBB handler: " + action.toString());
Kenny Root02c87302010-07-01 08:10:18 -07002559 }
2560
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002561 @Override
2562 public void unmountObb(String rawPath, boolean force, IObbActionListener token, int nonce) {
2563 Preconditions.checkNotNull(rawPath, "rawPath cannot be null");
2564
2565 final ObbState existingState;
Rubin Xucd7a0142015-04-17 23:45:27 +01002566 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002567 existingState = mObbPathToStateMap.get(rawPath);
Kenny Rootf1121dc2010-09-29 07:30:53 -07002568 }
2569
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002570 if (existingState != null) {
2571 // TODO: separate state object from request data
2572 final int callingUid = Binder.getCallingUid();
2573 final ObbState newState = new ObbState(
2574 rawPath, existingState.canonicalPath, callingUid, token, nonce);
2575 final ObbAction action = new UnmountObbAction(newState, force);
2576 mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
Kenny Root02c87302010-07-01 08:10:18 -07002577
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07002578 if (DEBUG_OBB)
2579 Slog.i(TAG, "Send to OBB handler: " + action.toString());
2580 } else {
2581 Slog.w(TAG, "Unknown OBB mount at " + rawPath);
2582 }
Kenny Roota02b8b02010-08-05 16:14:17 -07002583 }
2584
Ben Komalo444eca22011-09-01 15:17:44 -07002585 @Override
2586 public int getEncryptionState() {
2587 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2588 "no permission to access the crypt keeper");
2589
2590 waitForReady();
2591
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002592 final NativeDaemonEvent event;
Ben Komalo444eca22011-09-01 15:17:44 -07002593 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002594 event = mCryptConnector.execute("cryptfs", "cryptocomplete");
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002595 return Integer.parseInt(event.getMessage());
Ben Komalo444eca22011-09-01 15:17:44 -07002596 } catch (NumberFormatException e) {
2597 // Bad result - unexpected.
2598 Slog.w(TAG, "Unable to parse result from cryptfs cryptocomplete");
Sudheer Shankaf7341142016-10-18 17:15:18 -07002599 return StorageManager.ENCRYPTION_STATE_ERROR_UNKNOWN;
Ben Komalo444eca22011-09-01 15:17:44 -07002600 } catch (NativeDaemonConnectorException e) {
2601 // Something bad happened.
2602 Slog.w(TAG, "Error in communicating with cryptfs in validating");
Sudheer Shankaf7341142016-10-18 17:15:18 -07002603 return StorageManager.ENCRYPTION_STATE_ERROR_UNKNOWN;
Ben Komalo444eca22011-09-01 15:17:44 -07002604 }
2605 }
2606
2607 @Override
Jason parks5af0b912010-11-29 09:05:25 -06002608 public int decryptStorage(String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002609 if (TextUtils.isEmpty(password)) {
2610 throw new IllegalArgumentException("password cannot be empty");
Jason parks5af0b912010-11-29 09:05:25 -06002611 }
2612
Jason parks8888c592011-01-20 22:46:41 -06002613 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2614 "no permission to access the crypt keeper");
Jason parks5af0b912010-11-29 09:05:25 -06002615
2616 waitForReady();
2617
2618 if (DEBUG_EVENTS) {
2619 Slog.i(TAG, "decrypting storage...");
2620 }
2621
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002622 final NativeDaemonEvent event;
Jason parks5af0b912010-11-29 09:05:25 -06002623 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002624 event = mCryptConnector.execute("cryptfs", "checkpw", new SensitiveArg(password));
Jason parks9ed98bc2011-01-17 09:58:35 -06002625
Fredrik Roubertda6aedf2011-12-20 17:34:43 +01002626 final int code = Integer.parseInt(event.getMessage());
Jason parks9ed98bc2011-01-17 09:58:35 -06002627 if (code == 0) {
2628 // Decrypt was successful. Post a delayed message before restarting in order
2629 // to let the UI to clear itself
2630 mHandler.postDelayed(new Runnable() {
2631 public void run() {
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002632 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002633 mCryptConnector.execute("cryptfs", "restart");
Jeff Sharkey31c6e482011-11-18 17:09:01 -08002634 } catch (NativeDaemonConnectorException e) {
2635 Slog.e(TAG, "problem executing in background", e);
2636 }
Jason parks9ed98bc2011-01-17 09:58:35 -06002637 }
Jason parksf7b3cd42011-01-27 09:28:25 -06002638 }, 1000); // 1 second
Jason parks9ed98bc2011-01-17 09:58:35 -06002639 }
2640
2641 return code;
Jason parks5af0b912010-11-29 09:05:25 -06002642 } catch (NativeDaemonConnectorException e) {
2643 // Decryption failed
2644 return e.getCode();
2645 }
Jason parks5af0b912010-11-29 09:05:25 -06002646 }
2647
Paul Lawrence46791e72014-04-03 09:10:26 -07002648 public int encryptStorage(int type, String password) {
2649 if (TextUtils.isEmpty(password) && type != StorageManager.CRYPT_TYPE_DEFAULT) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002650 throw new IllegalArgumentException("password cannot be empty");
Jason parks56aa5322011-01-07 09:01:15 -06002651 }
2652
Jason parks8888c592011-01-20 22:46:41 -06002653 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2654 "no permission to access the crypt keeper");
Jason parks56aa5322011-01-07 09:01:15 -06002655
2656 waitForReady();
2657
2658 if (DEBUG_EVENTS) {
Jason parks8888c592011-01-20 22:46:41 -06002659 Slog.i(TAG, "encrypting storage...");
Jason parks56aa5322011-01-07 09:01:15 -06002660 }
2661
2662 try {
Paul Lawrence5096d9e2015-09-09 13:05:45 -07002663 if (type == StorageManager.CRYPT_TYPE_DEFAULT) {
2664 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2665 CRYPTO_TYPES[type]);
2666 } else {
2667 mCryptConnector.execute("cryptfs", "enablecrypto", "inplace",
2668 CRYPTO_TYPES[type], new SensitiveArg(password));
2669 }
Jason parks56aa5322011-01-07 09:01:15 -06002670 } catch (NativeDaemonConnectorException e) {
2671 // Encryption failed
2672 return e.getCode();
2673 }
2674
2675 return 0;
2676 }
2677
Paul Lawrence8e397362014-01-27 15:22:30 -08002678 /** Set the password for encrypting the master key.
2679 * @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
2680 * @param password The password to set.
2681 */
2682 public int changeEncryptionPassword(int type, String password) {
Jason parksf7b3cd42011-01-27 09:28:25 -06002683 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2684 "no permission to access the crypt keeper");
2685
2686 waitForReady();
2687
2688 if (DEBUG_EVENTS) {
2689 Slog.i(TAG, "changing encryption password...");
2690 }
2691
2692 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002693 NativeDaemonEvent event = mCryptConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type],
Paul Lawrence05487612015-06-09 13:35:38 -07002694 new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002695 return Integer.parseInt(event.getMessage());
Jason parksf7b3cd42011-01-27 09:28:25 -06002696 } catch (NativeDaemonConnectorException e) {
2697 // Encryption failed
2698 return e.getCode();
2699 }
2700 }
2701
Christopher Tate32418be2011-10-10 13:51:12 -07002702 /**
2703 * Validate a user-supplied password string with cryptfs
2704 */
2705 @Override
2706 public int verifyEncryptionPassword(String password) throws RemoteException {
2707 // Only the system process is permitted to validate passwords
2708 if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
2709 throw new SecurityException("no permission to access the crypt keeper");
2710 }
2711
2712 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
2713 "no permission to access the crypt keeper");
2714
2715 if (TextUtils.isEmpty(password)) {
2716 throw new IllegalArgumentException("password cannot be empty");
2717 }
2718
2719 waitForReady();
2720
2721 if (DEBUG_EVENTS) {
2722 Slog.i(TAG, "validating encryption password...");
2723 }
2724
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002725 final NativeDaemonEvent event;
Christopher Tate32418be2011-10-10 13:51:12 -07002726 try {
Paul Lawrence05487612015-06-09 13:35:38 -07002727 event = mCryptConnector.execute("cryptfs", "verifypw", new SensitiveArg(password));
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08002728 Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
2729 return Integer.parseInt(event.getMessage());
Christopher Tate32418be2011-10-10 13:51:12 -07002730 } catch (NativeDaemonConnectorException e) {
2731 // Encryption failed
2732 return e.getCode();
2733 }
2734 }
2735
Paul Lawrence8e397362014-01-27 15:22:30 -08002736 /**
2737 * Get the type of encryption used to encrypt the master key.
2738 * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
2739 */
2740 @Override
Svetoslav16e4a1a2014-09-29 18:16:20 -07002741 public int getPasswordType() {
Paul Lawrence76a40572017-03-15 11:08:04 -07002742 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Paul Lawrence9de713d2016-05-02 22:45:33 +00002743 "no permission to access the crypt keeper");
2744
Paul Lawrence8e397362014-01-27 15:22:30 -08002745 waitForReady();
2746
2747 final NativeDaemonEvent event;
2748 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002749 event = mCryptConnector.execute("cryptfs", "getpwtype");
Paul Lawrence8e397362014-01-27 15:22:30 -08002750 for (int i = 0; i < CRYPTO_TYPES.length; ++i) {
2751 if (CRYPTO_TYPES[i].equals(event.getMessage()))
2752 return i;
2753 }
2754
2755 throw new IllegalStateException("unexpected return from cryptfs");
2756 } catch (NativeDaemonConnectorException e) {
2757 throw e.rethrowAsParcelableException();
2758 }
2759 }
2760
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002761 /**
2762 * Set a field in the crypto header.
2763 * @param field field to set
2764 * @param contents contents to set in field
2765 */
2766 @Override
2767 public void setField(String field, String contents) throws RemoteException {
Paul Lawrence76a40572017-03-15 11:08:04 -07002768 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002769 "no permission to access the crypt keeper");
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002770
2771 waitForReady();
2772
2773 final NativeDaemonEvent event;
2774 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002775 event = mCryptConnector.execute("cryptfs", "setfield", field, contents);
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002776 } catch (NativeDaemonConnectorException e) {
2777 throw e.rethrowAsParcelableException();
2778 }
2779 }
2780
2781 /**
2782 * Gets a field from the crypto header.
2783 * @param field field to get
2784 * @return contents of field
2785 */
2786 @Override
2787 public String getField(String field) throws RemoteException {
Paul Lawrence76a40572017-03-15 11:08:04 -07002788 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002789 "no permission to access the crypt keeper");
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002790
2791 waitForReady();
2792
2793 final NativeDaemonEvent event;
2794 try {
2795 final String[] contents = NativeDaemonEvent.filterMessageList(
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002796 mCryptConnector.executeForList("cryptfs", "getfield", field),
Paul Lawrencee51dcf92014-03-18 10:56:00 -07002797 VoldResponseCode.CryptfsGetfieldResult);
2798 String result = new String();
2799 for (String content : contents) {
2800 result += content;
2801 }
2802 return result;
2803 } catch (NativeDaemonConnectorException e) {
2804 throw e.rethrowAsParcelableException();
2805 }
2806 }
2807
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002808 /**
2809 * Is userdata convertible to file based encryption?
2810 * @return non zero for convertible
2811 */
2812 @Override
2813 public boolean isConvertibleToFBE() throws RemoteException {
Paul Lawrence76a40572017-03-15 11:08:04 -07002814 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002815 "no permission to access the crypt keeper");
Paul Lawrence3806d9c2015-10-29 10:30:46 -07002816
2817 waitForReady();
2818
2819 final NativeDaemonEvent event;
2820 try {
2821 event = mCryptConnector.execute("cryptfs", "isConvertibleToFBE");
2822 return Integer.parseInt(event.getMessage()) != 0;
2823 } catch (NativeDaemonConnectorException e) {
2824 throw e.rethrowAsParcelableException();
2825 }
2826 }
2827
Jeff Sharkeyb049e212012-09-07 23:16:01 -07002828 @Override
Paul Lawrence945490c2014-03-27 16:37:28 +00002829 public String getPassword() throws RemoteException {
Paul Lawrence76a40572017-03-15 11:08:04 -07002830 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Rubin Xucd7a0142015-04-17 23:45:27 +01002831 "only keyguard can retrieve password");
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002832
Paul Lawrence945490c2014-03-27 16:37:28 +00002833 if (!isReady()) {
2834 return new String();
2835 }
2836
2837 final NativeDaemonEvent event;
2838 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002839 event = mCryptConnector.execute("cryptfs", "getpw");
Paul Lawrence24063b52015-01-06 13:11:23 -08002840 if ("-1".equals(event.getMessage())) {
2841 // -1 equals no password
2842 return null;
2843 }
Paul Lawrence05487612015-06-09 13:35:38 -07002844 return event.getMessage();
Paul Lawrence945490c2014-03-27 16:37:28 +00002845 } catch (NativeDaemonConnectorException e) {
2846 throw e.rethrowAsParcelableException();
Paul Lawrence24063b52015-01-06 13:11:23 -08002847 } catch (IllegalArgumentException e) {
2848 Slog.e(TAG, "Invalid response to getPassword");
2849 return null;
Paul Lawrence945490c2014-03-27 16:37:28 +00002850 }
2851 }
2852
2853 @Override
2854 public void clearPassword() throws RemoteException {
Paul Lawrence76a40572017-03-15 11:08:04 -07002855 mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
Paul Lawrence0bbd1082016-04-26 15:21:02 -07002856 "only keyguard can clear password");
2857
Paul Lawrence945490c2014-03-27 16:37:28 +00002858 if (!isReady()) {
2859 return;
2860 }
2861
2862 final NativeDaemonEvent event;
2863 try {
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07002864 event = mCryptConnector.execute("cryptfs", "clearpw");
Paul Lawrence945490c2014-03-27 16:37:28 +00002865 } catch (NativeDaemonConnectorException e) {
2866 throw e.rethrowAsParcelableException();
2867 }
2868 }
2869
2870 @Override
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002871 public void createUserKey(int userId, int serialNumber, boolean ephemeral) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002872 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002873 waitForReady();
2874
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002875 try {
Lenka Trochtovac4dd0212015-11-18 12:22:06 +01002876 mCryptConnector.execute("cryptfs", "create_user_key", userId, serialNumber,
2877 ephemeral ? 1 : 0);
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002878 } catch (NativeDaemonConnectorException e) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002879 throw e.rethrowAsParcelableException();
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002880 }
2881 }
2882
Paul Crowley7ec733f2015-05-19 12:42:00 +01002883 @Override
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002884 public void destroyUserKey(int userId) {
2885 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
Paul Crowley7ec733f2015-05-19 12:42:00 +01002886 waitForReady();
2887
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002888 try {
2889 mCryptConnector.execute("cryptfs", "destroy_user_key", userId);
2890 } catch (NativeDaemonConnectorException e) {
2891 throw e.rethrowAsParcelableException();
2892 }
2893 }
2894
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002895 private SensitiveArg encodeBytes(byte[] bytes) {
2896 if (ArrayUtils.isEmpty(bytes)) {
2897 return new SensitiveArg("!");
2898 } else {
2899 return new SensitiveArg(HexDump.toHexString(bytes));
2900 }
2901 }
2902
Paul Crowleycc701552016-05-17 14:18:49 -07002903 /*
2904 * Add this token/secret pair to the set of ways we can recover a disk encryption key.
2905 * Changing the token/secret for a disk encryption key is done in two phases: first, adding
2906 * a new token/secret pair with this call, then delting all other pairs with
2907 * fixateNewestUserKeyAuth. This allows other places where a credential is used, such as
2908 * Gatekeeper, to be updated between the two calls.
2909 */
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002910 @Override
Paul Crowleycc701552016-05-17 14:18:49 -07002911 public void addUserKeyAuth(int userId, int serialNumber, byte[] token, byte[] secret) {
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002912 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2913 waitForReady();
2914
2915 try {
Paul Crowleycc701552016-05-17 14:18:49 -07002916 mCryptConnector.execute("cryptfs", "add_user_key_auth", userId, serialNumber,
2917 encodeBytes(token), encodeBytes(secret));
2918 } catch (NativeDaemonConnectorException e) {
2919 throw e.rethrowAsParcelableException();
2920 }
2921 }
2922
2923 /*
2924 * Delete all disk encryption token/secret pairs except the most recently added one
2925 */
2926 @Override
2927 public void fixateNewestUserKeyAuth(int userId) {
2928 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2929 waitForReady();
2930
2931 try {
2932 mCryptConnector.execute("cryptfs", "fixate_newest_user_key_auth", userId);
Paul Crowleyfaeb3eb2016-02-08 15:58:29 +00002933 } catch (NativeDaemonConnectorException e) {
2934 throw e.rethrowAsParcelableException();
2935 }
2936 }
2937
2938 @Override
2939 public void unlockUserKey(int userId, int serialNumber, byte[] token, byte[] secret) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002940 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2941 waitForReady();
2942
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002943 if (StorageManager.isFileEncryptedNativeOrEmulated()) {
Rubin Xu3bf722a2016-12-15 16:07:38 +00002944 // When a user has secure lock screen, require secret to actually unlock.
2945 // This check is mostly in place for emulation mode.
2946 if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(secret)) {
2947 throw new IllegalStateException("Secret required to unlock secure user " + userId);
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002948 }
Jeff Sharkeyb9fe5372015-12-03 15:23:08 -07002949
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002950 try {
2951 mCryptConnector.execute("cryptfs", "unlock_user_key", userId, serialNumber,
2952 encodeBytes(token), encodeBytes(secret));
2953 } catch (NativeDaemonConnectorException e) {
2954 throw e.rethrowAsParcelableException();
2955 }
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002956 }
2957
2958 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002959 mLocalUnlockedUsers = ArrayUtils.appendInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002960 }
2961 }
2962
2963 @Override
2964 public void lockUserKey(int userId) {
2965 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2966 waitForReady();
2967
2968 try {
2969 mCryptConnector.execute("cryptfs", "lock_user_key", userId);
2970 } catch (NativeDaemonConnectorException e) {
2971 throw e.rethrowAsParcelableException();
2972 }
2973
2974 synchronized (mLock) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07002975 mLocalUnlockedUsers = ArrayUtils.removeInt(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002976 }
2977 }
2978
2979 @Override
2980 public boolean isUserKeyUnlocked(int userId) {
Jeff Sharkeyce18c812016-04-27 16:00:41 -06002981 synchronized (mLock) {
2982 return ArrayUtils.contains(mLocalUnlockedUsers, userId);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002983 }
2984 }
2985
2986 @Override
Jeff Sharkey47f71082016-02-01 17:03:54 -07002987 public void prepareUserStorage(String volumeUuid, int userId, int serialNumber, int flags) {
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002988 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
2989 waitForReady();
2990
2991 try {
2992 mCryptConnector.execute("cryptfs", "prepare_user_storage", escapeNull(volumeUuid),
Jeff Sharkey47f71082016-02-01 17:03:54 -07002993 userId, serialNumber, flags);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08002994 } catch (NativeDaemonConnectorException e) {
2995 throw e.rethrowAsParcelableException();
Paul Crowley7ec733f2015-05-19 12:42:00 +01002996 }
2997 }
2998
Paul Crowleybcf48ed2015-04-22 13:36:59 +01002999 @Override
Jeff Sharkeyfcf1e552016-04-14 20:44:58 -06003000 public void destroyUserStorage(String volumeUuid, int userId, int flags) {
3001 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
3002 waitForReady();
3003
3004 try {
3005 mCryptConnector.execute("cryptfs", "destroy_user_storage", escapeNull(volumeUuid),
3006 userId, flags);
3007 } catch (NativeDaemonConnectorException e) {
3008 throw e.rethrowAsParcelableException();
3009 }
3010 }
3011
Rubin Xuee67b612017-04-27 17:01:05 +01003012 @Override
3013 public void secdiscard(String path) {
3014 enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
3015 waitForReady();
3016
3017 try {
3018 mCryptConnector.execute("cryptfs", "secdiscard", escapeNull(path));
3019 } catch (NativeDaemonConnectorException e) {
3020 throw e.rethrowAsParcelableException();
3021 }
3022 }
3023
Daichi Hironoe56740d2017-02-02 13:56:45 +09003024 class AppFuseMountScope extends AppFuseBridge.MountScope {
Daichi Hirono812c95d2017-02-08 16:20:20 +09003025 boolean opened = false;
3026
3027 public AppFuseMountScope(int uid, int pid, int mountId) {
3028 super(uid, pid, mountId);
3029 }
3030
3031 @Override
3032 public ParcelFileDescriptor open() throws NativeDaemonConnectorException {
3033 final NativeDaemonEvent event = StorageManagerService.this.mConnector.execute(
3034 "appfuse", "mount", uid, Process.myPid(), mountId);
3035 opened = true;
3036 if (event.getFileDescriptors() == null ||
3037 event.getFileDescriptors().length == 0) {
3038 throw new NativeDaemonConnectorException("Cannot obtain device FD");
3039 }
3040 return new ParcelFileDescriptor(event.getFileDescriptors()[0]);
Daichi Hirono9fb00182016-11-08 14:12:17 +09003041 }
3042
3043 @Override
Daichi Hironoe56740d2017-02-02 13:56:45 +09003044 public void close() throws Exception {
Daichi Hirono812c95d2017-02-08 16:20:20 +09003045 if (opened) {
3046 mConnector.execute("appfuse", "unmount", uid, Process.myPid(), mountId);
3047 opened = false;
3048 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09003049 }
3050 }
3051
3052 @Override
Daichi Hirono812c95d2017-02-08 16:20:20 +09003053 public @Nullable AppFuseMount mountProxyFileDescriptorBridge() {
Daichi Hironoe56740d2017-02-02 13:56:45 +09003054 Slog.v(TAG, "mountProxyFileDescriptorBridge");
Daichi Hirono9fb00182016-11-08 14:12:17 +09003055 final int uid = Binder.getCallingUid();
3056 final int pid = Binder.getCallingPid();
Daichi Hirono9fb00182016-11-08 14:12:17 +09003057
Daichi Hironoe56740d2017-02-02 13:56:45 +09003058 while (true) {
3059 synchronized (mAppFuseLock) {
3060 boolean newlyCreated = false;
3061 if (mAppFuseBridge == null) {
3062 mAppFuseBridge = new AppFuseBridge();
3063 new Thread(mAppFuseBridge, AppFuseBridge.TAG).start();
3064 newlyCreated = true;
Daichi Hirono9fb00182016-11-08 14:12:17 +09003065 }
Daichi Hironoe56740d2017-02-02 13:56:45 +09003066 try {
3067 final int name = mNextAppFuseName++;
3068 try {
3069 return new AppFuseMount(
Daichi Hirono812c95d2017-02-08 16:20:20 +09003070 name, mAppFuseBridge.addBridge(new AppFuseMountScope(uid, pid, name)));
3071 } catch (FuseUnavailableMountException e) {
Daichi Hironoe56740d2017-02-02 13:56:45 +09003072 if (newlyCreated) {
3073 // If newly created bridge fails, it's a real error.
Daichi Hirono812c95d2017-02-08 16:20:20 +09003074 Slog.e(TAG, "", e);
3075 return null;
Daichi Hironoe56740d2017-02-02 13:56:45 +09003076 }
3077 // It seems the thread of mAppFuseBridge has already been terminated.
3078 mAppFuseBridge = null;
3079 }
3080 } catch (NativeDaemonConnectorException e) {
3081 throw e.rethrowAsParcelableException();
3082 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09003083 }
Daichi Hirono9fb00182016-11-08 14:12:17 +09003084 }
3085 }
3086
3087 @Override
Daichi Hirono812c95d2017-02-08 16:20:20 +09003088 public @Nullable ParcelFileDescriptor openProxyFileDescriptor(
3089 int mountId, int fileId, int mode) {
3090 Slog.v(TAG, "mountProxyFileDescriptor");
Daichi Hirono9fb00182016-11-08 14:12:17 +09003091 final int pid = Binder.getCallingPid();
3092 try {
3093 synchronized (mAppFuseLock) {
Daichi Hironoe56740d2017-02-02 13:56:45 +09003094 if (mAppFuseBridge == null) {
Daichi Hirono812c95d2017-02-08 16:20:20 +09003095 Slog.e(TAG, "FuseBridge has not been created");
3096 return null;
Daichi Hirono9fb00182016-11-08 14:12:17 +09003097 }
Daichi Hironoe56740d2017-02-02 13:56:45 +09003098 return mAppFuseBridge.openFile(pid, mountId, fileId, mode);
Daichi Hirono9fb00182016-11-08 14:12:17 +09003099 }
Daichi Hirono812c95d2017-02-08 16:20:20 +09003100 } catch (FuseUnavailableMountException | InterruptedException error) {
3101 Slog.v(TAG, "The mount point has already been invalid", error);
3102 return null;
Daichi Hirono9fb00182016-11-08 14:12:17 +09003103 }
3104 }
3105
Daichi Hirono9e8d9e22015-11-13 14:37:00 +09003106 @Override
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003107 public int mkdirs(String callingPkg, String appPath) {
3108 final int userId = UserHandle.getUserId(Binder.getCallingUid());
3109 final UserEnvironment userEnv = new UserEnvironment(userId);
3110
3111 // Validate that reported package name belongs to caller
3112 final AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
3113 Context.APP_OPS_SERVICE);
3114 appOps.checkPackage(Binder.getCallingUid(), callingPkg);
3115
Jeff Sharkey48877892015-03-18 11:27:19 -07003116 File appFile = null;
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003117 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07003118 appFile = new File(appPath).getCanonicalFile();
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003119 } catch (IOException e) {
3120 Slog.e(TAG, "Failed to resolve " + appPath + ": " + e);
3121 return -1;
3122 }
3123
3124 // Try translating the app path into a vold path, but require that it
3125 // belong to the calling package.
Jeff Sharkey48877892015-03-18 11:27:19 -07003126 if (FileUtils.contains(userEnv.buildExternalStorageAppDataDirs(callingPkg), appFile) ||
3127 FileUtils.contains(userEnv.buildExternalStorageAppObbDirs(callingPkg), appFile) ||
3128 FileUtils.contains(userEnv.buildExternalStorageAppMediaDirs(callingPkg), appFile)) {
3129 appPath = appFile.getAbsolutePath();
3130 if (!appPath.endsWith("/")) {
3131 appPath = appPath + "/";
3132 }
3133
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003134 try {
Jeff Sharkey48877892015-03-18 11:27:19 -07003135 mConnector.execute("volume", "mkdirs", appPath);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003136 return 0;
3137 } catch (NativeDaemonConnectorException e) {
3138 return e.getCode();
3139 }
3140 }
3141
Jeff Sharkey48877892015-03-18 11:27:19 -07003142 throw new SecurityException("Invalid mkdirs path: " + appFile);
Jeff Sharkey2d8b4e82013-09-17 17:30:33 -07003143 }
3144
3145 @Override
Jeff Sharkey46349872015-07-28 10:49:47 -07003146 public StorageVolume[] getVolumeList(int uid, String packageName, int flags) {
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003147 final int userId = UserHandle.getUserId(uid);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003148
Jeff Sharkey46349872015-07-28 10:49:47 -07003149 final boolean forWrite = (flags & StorageManager.FLAG_FOR_WRITE) != 0;
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003150 final boolean realState = (flags & StorageManager.FLAG_REAL_STATE) != 0;
3151 final boolean includeInvisible = (flags & StorageManager.FLAG_INCLUDE_INVISIBLE) != 0;
Jeff Sharkey46349872015-07-28 10:49:47 -07003152
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003153 final boolean userKeyUnlocked;
3154 final boolean storagePermission;
3155 final long token = Binder.clearCallingIdentity();
Svetoslav38c3dbb2015-07-14 11:27:06 -07003156 try {
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003157 userKeyUnlocked = isUserKeyUnlocked(userId);
Sudheer Shanka2250d562016-11-07 15:41:02 -08003158 storagePermission = mStorageManagerInternal.hasExternalStorage(uid, packageName);
Svetoslav38c3dbb2015-07-14 11:27:06 -07003159 } finally {
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003160 Binder.restoreCallingIdentity(token);
Svetoslav38c3dbb2015-07-14 11:27:06 -07003161 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07003162
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003163 boolean foundPrimary = false;
3164
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003165 final ArrayList<StorageVolume> res = new ArrayList<>();
Jeff Sharkey48877892015-03-18 11:27:19 -07003166 synchronized (mLock) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003167 for (int i = 0; i < mVolumes.size(); i++) {
3168 final VolumeInfo vol = mVolumes.valueAt(i);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003169 switch (vol.getType()) {
3170 case VolumeInfo.TYPE_PUBLIC:
3171 case VolumeInfo.TYPE_EMULATED:
3172 break;
3173 default:
3174 continue;
3175 }
3176
3177 boolean match = false;
3178 if (forWrite) {
3179 match = vol.isVisibleForWrite(userId);
3180 } else {
Felipe Leme123a0e72016-06-10 11:09:11 -07003181 match = vol.isVisibleForRead(userId)
3182 || (includeInvisible && vol.getPath() != null);
Jeff Sharkeyc02bfae2016-03-27 15:06:53 -06003183 }
3184 if (!match) continue;
3185
3186 boolean reportUnmounted = false;
3187 if ((vol.getType() == VolumeInfo.TYPE_EMULATED) && !userKeyUnlocked) {
3188 reportUnmounted = true;
3189 } else if (!storagePermission && !realState) {
3190 reportUnmounted = true;
3191 }
3192
3193 final StorageVolume userVol = vol.buildStorageVolume(mContext, userId,
3194 reportUnmounted);
3195 if (vol.isPrimary()) {
3196 res.add(0, userVol);
3197 foundPrimary = true;
3198 } else {
3199 res.add(userVol);
Jeff Sharkeyb049e212012-09-07 23:16:01 -07003200 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003201 }
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003202 }
Jeff Sharkey48877892015-03-18 11:27:19 -07003203
3204 if (!foundPrimary) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003205 Log.w(TAG, "No primary storage defined yet; hacking together a stub");
Jeff Sharkey48877892015-03-18 11:27:19 -07003206
3207 final boolean primaryPhysical = SystemProperties.getBoolean(
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003208 StorageManager.PROP_PRIMARY_PHYSICAL, false);
Jeff Sharkey48877892015-03-18 11:27:19 -07003209
3210 final String id = "stub_primary";
3211 final File path = Environment.getLegacyExternalStorageDirectory();
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003212 final String description = mContext.getString(android.R.string.unknownName);
Jeff Sharkey48877892015-03-18 11:27:19 -07003213 final boolean primary = true;
3214 final boolean removable = primaryPhysical;
3215 final boolean emulated = !primaryPhysical;
3216 final long mtpReserveSize = 0L;
3217 final boolean allowMassStorage = false;
3218 final long maxFileSize = 0L;
3219 final UserHandle owner = new UserHandle(userId);
3220 final String uuid = null;
Jeff Sharkey48877892015-03-18 11:27:19 -07003221 final String state = Environment.MEDIA_REMOVED;
3222
Jeff Sharkey5af1835d2015-07-07 17:26:59 -07003223 res.add(0, new StorageVolume(id, StorageVolume.STORAGE_ID_INVALID, path,
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003224 description, primary, removable, emulated, mtpReserveSize,
3225 allowMassStorage, maxFileSize, owner, uuid, state));
Jeff Sharkey48877892015-03-18 11:27:19 -07003226 }
3227
3228 return res.toArray(new StorageVolume[res.size()]);
Mike Lockwood8fa5f802011-03-24 08:12:30 -07003229 }
3230
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003231 @Override
3232 public DiskInfo[] getDisks() {
3233 synchronized (mLock) {
3234 final DiskInfo[] res = new DiskInfo[mDisks.size()];
3235 for (int i = 0; i < mDisks.size(); i++) {
3236 res[i] = mDisks.valueAt(i);
3237 }
3238 return res;
3239 }
3240 }
3241
3242 @Override
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003243 public VolumeInfo[] getVolumes(int flags) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -07003244 synchronized (mLock) {
3245 final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
3246 for (int i = 0; i < mVolumes.size(); i++) {
3247 res[i] = mVolumes.valueAt(i);
3248 }
3249 return res;
3250 }
3251 }
3252
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003253 @Override
3254 public VolumeRecord[] getVolumeRecords(int flags) {
3255 synchronized (mLock) {
3256 final VolumeRecord[] res = new VolumeRecord[mRecords.size()];
3257 for (int i = 0; i < mRecords.size(); i++) {
3258 res[i] = mRecords.valueAt(i);
3259 }
3260 return res;
3261 }
3262 }
3263
Jeff Sharkey9bed0702017-01-23 20:37:05 -07003264 @Override
3265 public long getCacheQuotaBytes(String volumeUuid, int uid) {
3266 if (uid != Binder.getCallingUid()) {
3267 mContext.enforceCallingPermission(android.Manifest.permission.STORAGE_INTERNAL, TAG);
3268 }
Daniel Nishi80fdb012017-03-09 14:30:07 -08003269 final long token = Binder.clearCallingIdentity();
3270 final StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class);
3271 try {
3272 return stats.getCacheQuotaBytes(volumeUuid, uid);
3273 } finally {
3274 Binder.restoreCallingIdentity(token);
3275 }
Jeff Sharkey9bed0702017-01-23 20:37:05 -07003276 }
3277
3278 @Override
3279 public long getCacheSizeBytes(String volumeUuid, int uid) {
3280 if (uid != Binder.getCallingUid()) {
3281 mContext.enforceCallingPermission(android.Manifest.permission.STORAGE_INTERNAL, TAG);
3282 }
3283 final long token = Binder.clearCallingIdentity();
3284 try {
3285 return mContext.getSystemService(StorageStatsManager.class)
3286 .queryStatsForUid(volumeUuid, uid).getCacheBytes();
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06003287 } catch (IOException e) {
3288 throw new ParcelableException(e);
Jeff Sharkey9bed0702017-01-23 20:37:05 -07003289 } finally {
3290 Binder.restoreCallingIdentity(token);
3291 }
3292 }
3293
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07003294 @Override
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003295 public long getAllocatableBytes(String volumeUuid, int flags) {
3296 final StorageManager storage = mContext.getSystemService(StorageManager.class);
3297 final StorageStatsManager stats = mContext.getSystemService(StorageStatsManager.class);
3298
3299 final boolean aggressive = (flags & StorageManager.FLAG_ALLOCATE_AGGRESSIVE) != 0;
3300 if (aggressive) {
3301 mContext.enforceCallingOrSelfPermission(
3302 android.Manifest.permission.ALLOCATE_AGGRESSIVE, TAG);
3303 }
3304
3305 final long token = Binder.clearCallingIdentity();
3306 try {
3307 // In general, apps can allocate as much space as they want, except
3308 // we never let them eat into either the minimum cache space or into
3309 // the low disk warning space.
3310 final File path = storage.findPathForUuid(volumeUuid);
3311 if (stats.isQuotaSupported(volumeUuid)) {
3312 if (aggressive) {
3313 return Math.max(0,
3314 stats.getFreeBytes(volumeUuid) - storage.getStorageFullBytes(path));
3315 } else {
3316 return Math.max(0,
3317 stats.getFreeBytes(volumeUuid) - storage.getStorageLowBytes(path)
3318 - storage.getStorageCacheBytes(path));
3319 }
3320 } else {
3321 // When we don't have fast quota information, we ignore cached
3322 // data and only consider unused bytes.
3323 if (aggressive) {
3324 return Math.max(0, path.getUsableSpace() - storage.getStorageFullBytes(path));
3325 } else {
3326 return Math.max(0, path.getUsableSpace() - storage.getStorageLowBytes(path));
3327 }
3328 }
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06003329 } catch (IOException e) {
3330 throw new ParcelableException(e);
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003331 } finally {
3332 Binder.restoreCallingIdentity(token);
3333 }
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07003334 }
3335
3336 @Override
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003337 public void allocateBytes(String volumeUuid, long bytes, int flags) {
3338 final StorageManager storage = mContext.getSystemService(StorageManager.class);
3339
3340 // This method call will enforce FLAG_ALLOCATE_AGGRESSIVE permissions so
3341 // we don't have to enforce them locally
3342 final long allocatableBytes = getAllocatableBytes(volumeUuid, flags);
3343 if (bytes > allocatableBytes) {
3344 throw new ParcelableException(new IOException("Failed to allocate " + bytes
3345 + " because only " + allocatableBytes + " allocatable"));
3346 }
3347
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003348 final long token = Binder.clearCallingIdentity();
3349 try {
Jeff Sharkey789a8fc2017-04-16 13:18:35 -06003350 // Free up enough disk space to satisfy both the requested allocation
3351 // and our low disk warning space.
3352 final File path = storage.findPathForUuid(volumeUuid);
3353 bytes += storage.getStorageLowBytes(path);
3354
Jeff Sharkeyd5d5e922017-02-21 10:51:23 -07003355 mPms.freeStorage(volumeUuid, bytes, flags);
3356 } catch (IOException e) {
3357 throw new ParcelableException(e);
3358 } finally {
3359 Binder.restoreCallingIdentity(token);
Jeff Sharkey500ce9e2017-02-12 02:39:24 -07003360 }
3361 }
3362
Kenny Rootaf9d6672010-10-08 09:21:39 -07003363 private void addObbStateLocked(ObbState obbState) throws RemoteException {
3364 final IBinder binder = obbState.getBinder();
3365 List<ObbState> obbStates = mObbMounts.get(binder);
Kenny Root5919ac62010-10-05 09:49:40 -07003366
Kenny Rootaf9d6672010-10-08 09:21:39 -07003367 if (obbStates == null) {
3368 obbStates = new ArrayList<ObbState>();
3369 mObbMounts.put(binder, obbStates);
3370 } else {
3371 for (final ObbState o : obbStates) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003372 if (o.rawPath.equals(obbState.rawPath)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003373 throw new IllegalStateException("Attempt to add ObbState twice. "
Sudheer Shanka2250d562016-11-07 15:41:02 -08003374 + "This indicates an error in the StorageManagerService logic.");
Kenny Root5919ac62010-10-05 09:49:40 -07003375 }
3376 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003377 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003378
3379 obbStates.add(obbState);
3380 try {
3381 obbState.link();
3382 } catch (RemoteException e) {
3383 /*
3384 * The binder died before we could link it, so clean up our state
3385 * and return failure.
3386 */
3387 obbStates.remove(obbState);
3388 if (obbStates.isEmpty()) {
3389 mObbMounts.remove(binder);
3390 }
3391
3392 // Rethrow the error so mountObb can get it
3393 throw e;
3394 }
3395
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003396 mObbPathToStateMap.put(obbState.rawPath, obbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003397 }
3398
Kenny Rootaf9d6672010-10-08 09:21:39 -07003399 private void removeObbStateLocked(ObbState obbState) {
3400 final IBinder binder = obbState.getBinder();
3401 final List<ObbState> obbStates = mObbMounts.get(binder);
3402 if (obbStates != null) {
3403 if (obbStates.remove(obbState)) {
3404 obbState.unlink();
Kenny Root05105f72010-09-22 17:29:43 -07003405 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003406 if (obbStates.isEmpty()) {
3407 mObbMounts.remove(binder);
3408 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003409 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003410
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003411 mObbPathToStateMap.remove(obbState.rawPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003412 }
3413
Kenny Roota02b8b02010-08-05 16:14:17 -07003414 private class ObbActionHandler extends Handler {
3415 private boolean mBound = false;
Kenny Root480afe72010-10-07 10:17:50 -07003416 private final List<ObbAction> mActions = new LinkedList<ObbAction>();
Kenny Roota02b8b02010-08-05 16:14:17 -07003417
3418 ObbActionHandler(Looper l) {
3419 super(l);
3420 }
3421
3422 @Override
3423 public void handleMessage(Message msg) {
3424 switch (msg.what) {
3425 case OBB_RUN_ACTION: {
Kenny Root480afe72010-10-07 10:17:50 -07003426 final ObbAction action = (ObbAction) msg.obj;
Kenny Roota02b8b02010-08-05 16:14:17 -07003427
3428 if (DEBUG_OBB)
3429 Slog.i(TAG, "OBB_RUN_ACTION: " + action.toString());
3430
3431 // If a bind was already initiated we don't really
3432 // need to do anything. The pending install
3433 // will be processed later on.
3434 if (!mBound) {
3435 // If this is the only one pending we might
3436 // have to bind to the service again.
3437 if (!connectToService()) {
3438 Slog.e(TAG, "Failed to bind to media container service");
3439 action.handleError();
3440 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003441 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003442 }
Kenny Root735de3b2010-09-30 14:11:39 -07003443
Kenny Root735de3b2010-09-30 14:11:39 -07003444 mActions.add(action);
Kenny Roota02b8b02010-08-05 16:14:17 -07003445 break;
3446 }
3447 case OBB_MCS_BOUND: {
3448 if (DEBUG_OBB)
3449 Slog.i(TAG, "OBB_MCS_BOUND");
3450 if (msg.obj != null) {
3451 mContainerService = (IMediaContainerService) msg.obj;
3452 }
3453 if (mContainerService == null) {
3454 // Something seriously wrong. Bail out
3455 Slog.e(TAG, "Cannot bind to media container service");
3456 for (ObbAction action : mActions) {
3457 // Indicate service bind error
3458 action.handleError();
3459 }
3460 mActions.clear();
3461 } else if (mActions.size() > 0) {
Kenny Root480afe72010-10-07 10:17:50 -07003462 final ObbAction action = mActions.get(0);
Kenny Roota02b8b02010-08-05 16:14:17 -07003463 if (action != null) {
3464 action.execute(this);
3465 }
3466 } else {
3467 // Should never happen ideally.
3468 Slog.w(TAG, "Empty queue");
3469 }
3470 break;
3471 }
3472 case OBB_MCS_RECONNECT: {
3473 if (DEBUG_OBB)
3474 Slog.i(TAG, "OBB_MCS_RECONNECT");
3475 if (mActions.size() > 0) {
3476 if (mBound) {
3477 disconnectService();
3478 }
3479 if (!connectToService()) {
3480 Slog.e(TAG, "Failed to bind to media container service");
3481 for (ObbAction action : mActions) {
3482 // Indicate service bind error
3483 action.handleError();
3484 }
3485 mActions.clear();
3486 }
3487 }
3488 break;
3489 }
3490 case OBB_MCS_UNBIND: {
3491 if (DEBUG_OBB)
3492 Slog.i(TAG, "OBB_MCS_UNBIND");
3493
3494 // Delete pending install
3495 if (mActions.size() > 0) {
3496 mActions.remove(0);
3497 }
3498 if (mActions.size() == 0) {
3499 if (mBound) {
3500 disconnectService();
3501 }
3502 } else {
3503 // There are more pending requests in queue.
3504 // Just post MCS_BOUND message to trigger processing
3505 // of next pending install.
3506 mObbActionHandler.sendEmptyMessage(OBB_MCS_BOUND);
3507 }
3508 break;
3509 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003510 case OBB_FLUSH_MOUNT_STATE: {
3511 final String path = (String) msg.obj;
3512
3513 if (DEBUG_OBB)
3514 Slog.i(TAG, "Flushing all OBB state for path " + path);
3515
3516 synchronized (mObbMounts) {
3517 final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>();
3518
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003519 final Iterator<ObbState> i = mObbPathToStateMap.values().iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003520 while (i.hasNext()) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003521 final ObbState state = i.next();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003522
3523 /*
3524 * If this entry's source file is in the volume path
3525 * that got unmounted, remove it because it's no
3526 * longer valid.
3527 */
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003528 if (state.canonicalPath.startsWith(path)) {
3529 obbStatesToRemove.add(state);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003530 }
3531 }
3532
3533 for (final ObbState obbState : obbStatesToRemove) {
3534 if (DEBUG_OBB)
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003535 Slog.i(TAG, "Removing state for " + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003536
3537 removeObbStateLocked(obbState);
3538
3539 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003540 obbState.token.onObbResult(obbState.rawPath, obbState.nonce,
Kenny Rootaf9d6672010-10-08 09:21:39 -07003541 OnObbStateChangeListener.UNMOUNTED);
3542 } catch (RemoteException e) {
3543 Slog.i(TAG, "Couldn't send unmount notification for OBB: "
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003544 + obbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003545 }
3546 }
3547 }
3548 break;
3549 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003550 }
3551 }
3552
3553 private boolean connectToService() {
3554 if (DEBUG_OBB)
3555 Slog.i(TAG, "Trying to bind to DefaultContainerService");
3556
3557 Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Jeff Sharkey6dce4962015-07-03 18:08:41 -07003558 if (mContext.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE,
Xiaohui Chene4de5a02015-09-22 15:33:31 -07003559 UserHandle.SYSTEM)) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003560 mBound = true;
3561 return true;
3562 }
3563 return false;
3564 }
3565
3566 private void disconnectService() {
3567 mContainerService = null;
3568 mBound = false;
3569 mContext.unbindService(mDefContainerConn);
3570 }
3571 }
3572
3573 abstract class ObbAction {
3574 private static final int MAX_RETRIES = 3;
3575 private int mRetries;
3576
3577 ObbState mObbState;
3578
3579 ObbAction(ObbState obbState) {
3580 mObbState = obbState;
3581 }
3582
3583 public void execute(ObbActionHandler handler) {
3584 try {
3585 if (DEBUG_OBB)
Ben Komalo444eca22011-09-01 15:17:44 -07003586 Slog.i(TAG, "Starting to execute action: " + toString());
Kenny Roota02b8b02010-08-05 16:14:17 -07003587 mRetries++;
3588 if (mRetries > MAX_RETRIES) {
3589 Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
Kenny Root480afe72010-10-07 10:17:50 -07003590 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003591 handleError();
Kenny Roota02b8b02010-08-05 16:14:17 -07003592 } else {
3593 handleExecute();
3594 if (DEBUG_OBB)
3595 Slog.i(TAG, "Posting install MCS_UNBIND");
3596 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
3597 }
3598 } catch (RemoteException e) {
3599 if (DEBUG_OBB)
3600 Slog.i(TAG, "Posting install MCS_RECONNECT");
3601 mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
3602 } catch (Exception e) {
3603 if (DEBUG_OBB)
3604 Slog.d(TAG, "Error handling OBB action", e);
3605 handleError();
Kenny Root17eb6fb2010-10-06 15:02:52 -07003606 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
Kenny Roota02b8b02010-08-05 16:14:17 -07003607 }
3608 }
3609
Kenny Root05105f72010-09-22 17:29:43 -07003610 abstract void handleExecute() throws RemoteException, IOException;
Kenny Roota02b8b02010-08-05 16:14:17 -07003611 abstract void handleError();
Kenny Root38cf8862010-09-26 14:18:51 -07003612
3613 protected ObbInfo getObbInfo() throws IOException {
3614 ObbInfo obbInfo;
3615 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003616 obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003617 } catch (RemoteException e) {
3618 Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003619 + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003620 obbInfo = null;
3621 }
3622 if (obbInfo == null) {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003623 throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath);
Kenny Root38cf8862010-09-26 14:18:51 -07003624 }
3625 return obbInfo;
3626 }
3627
Kenny Rootaf9d6672010-10-08 09:21:39 -07003628 protected void sendNewStatusOrIgnore(int status) {
3629 if (mObbState == null || mObbState.token == null) {
3630 return;
3631 }
3632
Kenny Root38cf8862010-09-26 14:18:51 -07003633 try {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003634 mObbState.token.onObbResult(mObbState.rawPath, mObbState.nonce, status);
Kenny Root38cf8862010-09-26 14:18:51 -07003635 } catch (RemoteException e) {
Sudheer Shanka2250d562016-11-07 15:41:02 -08003636 Slog.w(TAG, "StorageEventListener went away while calling onObbStateChanged");
Kenny Root38cf8862010-09-26 14:18:51 -07003637 }
3638 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003639 }
3640
3641 class MountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003642 private final String mKey;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003643 private final int mCallingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003644
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003645 MountObbAction(ObbState obbState, String key, int callingUid) {
Kenny Roota02b8b02010-08-05 16:14:17 -07003646 super(obbState);
3647 mKey = key;
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003648 mCallingUid = callingUid;
Kenny Roota02b8b02010-08-05 16:14:17 -07003649 }
3650
Jason parks5af0b912010-11-29 09:05:25 -06003651 @Override
Kenny Root735de3b2010-09-30 14:11:39 -07003652 public void handleExecute() throws IOException, RemoteException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003653 waitForReady();
3654 warnOnNotMounted();
3655
Kenny Root38cf8862010-09-26 14:18:51 -07003656 final ObbInfo obbInfo = getObbInfo();
3657
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003658 if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003659 Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
3660 + " which is owned by " + obbInfo.packageName);
3661 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3662 return;
Kenny Roota02b8b02010-08-05 16:14:17 -07003663 }
3664
Kenny Rootaf9d6672010-10-08 09:21:39 -07003665 final boolean isMounted;
3666 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003667 isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003668 }
3669 if (isMounted) {
3670 Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
3671 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
3672 return;
3673 }
3674
Kenny Rootaf9d6672010-10-08 09:21:39 -07003675 final String hashedKey;
3676 if (mKey == null) {
3677 hashedKey = "none";
3678 } else {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003679 try {
Kenny Root3b1abba2010-10-13 15:00:07 -07003680 SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
3681
3682 KeySpec ks = new PBEKeySpec(mKey.toCharArray(), obbInfo.salt,
3683 PBKDF2_HASH_ROUNDS, CRYPTO_ALGORITHM_KEY_SIZE);
3684 SecretKey key = factory.generateSecret(ks);
3685 BigInteger bi = new BigInteger(key.getEncoded());
3686 hashedKey = bi.toString(16);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003687 } catch (NoSuchAlgorithmException e) {
Kenny Root3b1abba2010-10-13 15:00:07 -07003688 Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
3689 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
3690 return;
3691 } catch (InvalidKeySpecException e) {
3692 Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
3693 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root38cf8862010-09-26 14:18:51 -07003694 return;
3695 }
Kenny Rootaf9d6672010-10-08 09:21:39 -07003696 }
Kenny Root38cf8862010-09-26 14:18:51 -07003697
Kenny Rootaf9d6672010-10-08 09:21:39 -07003698 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003699 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003700 mConnector.execute("obb", "mount", mObbState.canonicalPath, new SensitiveArg(hashedKey),
Jeff Sharkey56cd6462013-06-07 15:09:15 -07003701 mObbState.ownerGid);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003702 } catch (NativeDaemonConnectorException e) {
3703 int code = e.getCode();
3704 if (code != VoldResponseCode.OpFailedStorageBusy) {
3705 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003706 }
3707 }
3708
Kenny Rootaf9d6672010-10-08 09:21:39 -07003709 if (rc == StorageResultCode.OperationSucceeded) {
3710 if (DEBUG_OBB)
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003711 Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003712
3713 synchronized (mObbMounts) {
3714 addObbStateLocked(mObbState);
3715 }
3716
3717 sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
Kenny Root02c87302010-07-01 08:10:18 -07003718 } else {
Kenny Root05105f72010-09-22 17:29:43 -07003719 Slog.e(TAG, "Couldn't mount OBB file: " + rc);
Kenny Roota02b8b02010-08-05 16:14:17 -07003720
Kenny Rootaf9d6672010-10-08 09:21:39 -07003721 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
Kenny Root02c87302010-07-01 08:10:18 -07003722 }
3723 }
3724
Jason parks5af0b912010-11-29 09:05:25 -06003725 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003726 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003727 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Root02c87302010-07-01 08:10:18 -07003728 }
Kenny Roota02b8b02010-08-05 16:14:17 -07003729
3730 @Override
3731 public String toString() {
3732 StringBuilder sb = new StringBuilder();
3733 sb.append("MountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003734 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003735 sb.append('}');
3736 return sb.toString();
3737 }
3738 }
3739
3740 class UnmountObbAction extends ObbAction {
Ben Komalo444eca22011-09-01 15:17:44 -07003741 private final boolean mForceUnmount;
Kenny Roota02b8b02010-08-05 16:14:17 -07003742
3743 UnmountObbAction(ObbState obbState, boolean force) {
3744 super(obbState);
3745 mForceUnmount = force;
3746 }
3747
Jason parks5af0b912010-11-29 09:05:25 -06003748 @Override
Kenny Root38cf8862010-09-26 14:18:51 -07003749 public void handleExecute() throws IOException {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003750 waitForReady();
3751 warnOnNotMounted();
3752
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003753 final ObbState existingState;
Kenny Root38cf8862010-09-26 14:18:51 -07003754 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003755 existingState = mObbPathToStateMap.get(mObbState.rawPath);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003756 }
Kenny Root38cf8862010-09-26 14:18:51 -07003757
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003758 if (existingState == null) {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003759 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
3760 return;
3761 }
3762
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003763 if (existingState.ownerGid != mObbState.ownerGid) {
3764 Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
3765 + " (owned by GID " + existingState.ownerGid + ")");
Kenny Rootaf9d6672010-10-08 09:21:39 -07003766 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
3767 return;
3768 }
3769
Kenny Rootaf9d6672010-10-08 09:21:39 -07003770 int rc = StorageResultCode.OperationSucceeded;
Kenny Rootaf9d6672010-10-08 09:21:39 -07003771 try {
Xiaohui Chen621b3fc2015-10-02 14:41:42 -07003772 final Command cmd = new Command("obb", "unmount", mObbState.canonicalPath);
Jeff Sharkeydd519fa2011-12-02 14:11:21 -08003773 if (mForceUnmount) {
3774 cmd.appendArg("force");
3775 }
3776 mConnector.execute(cmd);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003777 } catch (NativeDaemonConnectorException e) {
3778 int code = e.getCode();
3779 if (code == VoldResponseCode.OpFailedStorageBusy) {
3780 rc = StorageResultCode.OperationFailedStorageBusy;
3781 } else if (code == VoldResponseCode.OpFailedStorageNotFound) {
3782 // If it's not mounted then we've already won.
3783 rc = StorageResultCode.OperationSucceeded;
3784 } else {
3785 rc = StorageResultCode.OperationFailedInternalError;
Kenny Roota02b8b02010-08-05 16:14:17 -07003786 }
3787 }
3788
Kenny Rootaf9d6672010-10-08 09:21:39 -07003789 if (rc == StorageResultCode.OperationSucceeded) {
3790 synchronized (mObbMounts) {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003791 removeObbStateLocked(existingState);
Kenny Root38cf8862010-09-26 14:18:51 -07003792 }
3793
Kenny Rootaf9d6672010-10-08 09:21:39 -07003794 sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
Kenny Roota02b8b02010-08-05 16:14:17 -07003795 } else {
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003796 Slog.w(TAG, "Could not unmount OBB: " + existingState);
Kenny Rootaf9d6672010-10-08 09:21:39 -07003797 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
Kenny Roota02b8b02010-08-05 16:14:17 -07003798 }
3799 }
3800
Jason parks5af0b912010-11-29 09:05:25 -06003801 @Override
Kenny Roota02b8b02010-08-05 16:14:17 -07003802 public void handleError() {
Kenny Rootaf9d6672010-10-08 09:21:39 -07003803 sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
Kenny Roota02b8b02010-08-05 16:14:17 -07003804 }
3805
3806 @Override
3807 public String toString() {
3808 StringBuilder sb = new StringBuilder();
3809 sb.append("UnmountObbAction{");
Jeff Sharkey4fbbda42012-09-24 18:34:07 -07003810 sb.append(mObbState);
Kenny Roota02b8b02010-08-05 16:14:17 -07003811 sb.append(",force=");
3812 sb.append(mForceUnmount);
Kenny Roota02b8b02010-08-05 16:14:17 -07003813 sb.append('}');
3814 return sb.toString();
3815 }
Kenny Root02c87302010-07-01 08:10:18 -07003816 }
Kenny Root38cf8862010-09-26 14:18:51 -07003817
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003818 private static class Callbacks extends Handler {
3819 private static final int MSG_STORAGE_STATE_CHANGED = 1;
3820 private static final int MSG_VOLUME_STATE_CHANGED = 2;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003821 private static final int MSG_VOLUME_RECORD_CHANGED = 3;
3822 private static final int MSG_VOLUME_FORGOTTEN = 4;
3823 private static final int MSG_DISK_SCANNED = 5;
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003824 private static final int MSG_DISK_DESTROYED = 6;
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003825
Sudheer Shanka2250d562016-11-07 15:41:02 -08003826 private final RemoteCallbackList<IStorageEventListener>
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003827 mCallbacks = new RemoteCallbackList<>();
3828
3829 public Callbacks(Looper looper) {
3830 super(looper);
3831 }
3832
Sudheer Shanka2250d562016-11-07 15:41:02 -08003833 public void register(IStorageEventListener callback) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003834 mCallbacks.register(callback);
3835 }
3836
Sudheer Shanka2250d562016-11-07 15:41:02 -08003837 public void unregister(IStorageEventListener callback) {
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003838 mCallbacks.unregister(callback);
3839 }
3840
3841 @Override
3842 public void handleMessage(Message msg) {
3843 final SomeArgs args = (SomeArgs) msg.obj;
3844 final int n = mCallbacks.beginBroadcast();
3845 for (int i = 0; i < n; i++) {
Sudheer Shanka2250d562016-11-07 15:41:02 -08003846 final IStorageEventListener callback = mCallbacks.getBroadcastItem(i);
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003847 try {
3848 invokeCallback(callback, msg.what, args);
3849 } catch (RemoteException ignored) {
3850 }
3851 }
3852 mCallbacks.finishBroadcast();
3853 args.recycle();
3854 }
3855
Sudheer Shanka2250d562016-11-07 15:41:02 -08003856 private void invokeCallback(IStorageEventListener callback, int what, SomeArgs args)
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003857 throws RemoteException {
3858 switch (what) {
3859 case MSG_STORAGE_STATE_CHANGED: {
3860 callback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
3861 (String) args.arg3);
3862 break;
3863 }
3864 case MSG_VOLUME_STATE_CHANGED: {
3865 callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
3866 break;
3867 }
Jeff Sharkey50a05452015-04-29 11:24:52 -07003868 case MSG_VOLUME_RECORD_CHANGED: {
3869 callback.onVolumeRecordChanged((VolumeRecord) args.arg1);
3870 break;
3871 }
3872 case MSG_VOLUME_FORGOTTEN: {
3873 callback.onVolumeForgotten((String) args.arg1);
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003874 break;
3875 }
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003876 case MSG_DISK_SCANNED: {
3877 callback.onDiskScanned((DiskInfo) args.arg1, args.argi2);
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003878 break;
3879 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003880 case MSG_DISK_DESTROYED: {
3881 callback.onDiskDestroyed((DiskInfo) args.arg1);
3882 break;
3883 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003884 }
3885 }
3886
3887 private void notifyStorageStateChanged(String path, String oldState, String newState) {
3888 final SomeArgs args = SomeArgs.obtain();
3889 args.arg1 = path;
3890 args.arg2 = oldState;
3891 args.arg3 = newState;
3892 obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
3893 }
3894
3895 private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
3896 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003897 args.arg1 = vol.clone();
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003898 args.argi2 = oldState;
3899 args.argi3 = newState;
3900 obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
3901 }
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003902
Jeff Sharkey50a05452015-04-29 11:24:52 -07003903 private void notifyVolumeRecordChanged(VolumeRecord rec) {
3904 final SomeArgs args = SomeArgs.obtain();
3905 args.arg1 = rec.clone();
3906 obtainMessage(MSG_VOLUME_RECORD_CHANGED, args).sendToTarget();
3907 }
3908
3909 private void notifyVolumeForgotten(String fsUuid) {
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003910 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003911 args.arg1 = fsUuid;
Jeff Sharkey50a05452015-04-29 11:24:52 -07003912 obtainMessage(MSG_VOLUME_FORGOTTEN, args).sendToTarget();
Jeff Sharkeyd95d3bf2015-04-14 21:39:44 -07003913 }
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003914
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003915 private void notifyDiskScanned(DiskInfo disk, int volumeCount) {
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003916 final SomeArgs args = SomeArgs.obtain();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003917 args.arg1 = disk.clone();
Jeff Sharkey620b32b2015-04-23 19:36:02 -07003918 args.argi2 = volumeCount;
3919 obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
Jeff Sharkey7e92ef32015-04-17 17:35:07 -07003920 }
Makoto Onuki9dc575d2015-06-12 16:10:25 -07003921
3922 private void notifyDiskDestroyed(DiskInfo disk) {
3923 final SomeArgs args = SomeArgs.obtain();
3924 args.arg1 = disk.clone();
3925 obtainMessage(MSG_DISK_DESTROYED, args).sendToTarget();
3926 }
Jeff Sharkey7151a9a2015-04-04 15:22:37 -07003927 }
3928
Kenny Root38cf8862010-09-26 14:18:51 -07003929 @Override
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003930 protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06003931 if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003932
3933 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003934 synchronized (mLock) {
3935 pw.println("Disks:");
3936 pw.increaseIndent();
3937 for (int i = 0; i < mDisks.size(); i++) {
3938 final DiskInfo disk = mDisks.valueAt(i);
3939 disk.dump(pw);
3940 }
3941 pw.decreaseIndent();
3942
3943 pw.println();
3944 pw.println("Volumes:");
3945 pw.increaseIndent();
3946 for (int i = 0; i < mVolumes.size(); i++) {
3947 final VolumeInfo vol = mVolumes.valueAt(i);
3948 if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.id)) continue;
3949 vol.dump(pw);
3950 }
3951 pw.decreaseIndent();
3952
3953 pw.println();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003954 pw.println("Records:");
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003955 pw.increaseIndent();
Jeff Sharkeyb36586a2015-04-27 08:42:28 -07003956 for (int i = 0; i < mRecords.size(); i++) {
3957 final VolumeRecord note = mRecords.valueAt(i);
3958 note.dump(pw);
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003959 }
3960 pw.decreaseIndent();
Jeff Sharkey275e3e42015-04-24 16:10:32 -07003961
3962 pw.println();
3963 pw.println("Primary storage UUID: " + mPrimaryStorageUuid);
Felipe Leme281389a2016-10-10 17:12:20 -07003964 final Pair<String, Long> pair = StorageManager.getPrimaryStoragePathAndSize();
3965 if (pair == null) {
3966 pw.println("Internal storage total size: N/A");
3967 } else {
3968 pw.print("Internal storage (");
3969 pw.print(pair.first);
3970 pw.print(") total size: ");
3971 pw.print(pair.second);
3972 pw.print(" (");
3973 pw.print((float) pair.second / TrafficStats.GB_IN_BYTES);
3974 pw.println(" GB)");
3975 }
Jeff Sharkey4c099d02015-05-15 13:45:00 -07003976 pw.println("Force adoptable: " + mForceAdoptable);
Jeff Sharkeyf9fc6d62015-11-08 16:46:05 -08003977 pw.println();
Jeff Sharkeyce14cd02015-12-07 15:35:42 -07003978 pw.println("Local unlocked users: " + Arrays.toString(mLocalUnlockedUsers));
3979 pw.println("System unlocked users: " + Arrays.toString(mSystemUnlockedUsers));
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003980 }
Kenny Root38cf8862010-09-26 14:18:51 -07003981
Kenny Root38cf8862010-09-26 14:18:51 -07003982 synchronized (mObbMounts) {
Jeff Sharkey27de30d2015-04-18 16:20:27 -07003983 pw.println();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003984 pw.println("mObbMounts:");
3985 pw.increaseIndent();
3986 final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet()
3987 .iterator();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003988 while (binders.hasNext()) {
3989 Entry<IBinder, List<ObbState>> e = binders.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003990 pw.println(e.getKey() + ":");
3991 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003992 final List<ObbState> obbStates = e.getValue();
Kenny Root38cf8862010-09-26 14:18:51 -07003993 for (final ObbState obbState : obbStates) {
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003994 pw.println(obbState);
Kenny Root38cf8862010-09-26 14:18:51 -07003995 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003996 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07003997 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07003998 pw.decreaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07003999
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004000 pw.println();
4001 pw.println("mObbPathToStateMap:");
4002 pw.increaseIndent();
Kenny Rootaf9d6672010-10-08 09:21:39 -07004003 final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator();
4004 while (maps.hasNext()) {
4005 final Entry<String, ObbState> e = maps.next();
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004006 pw.print(e.getKey());
4007 pw.print(" -> ");
4008 pw.println(e.getValue());
Kenny Rootaf9d6672010-10-08 09:21:39 -07004009 }
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004010 pw.decreaseIndent();
Kenny Root38cf8862010-09-26 14:18:51 -07004011 }
Kenny Root4161f9b2011-07-13 09:48:33 -07004012
Robert Greenwalt470fd722012-01-18 12:51:15 -08004013 pw.println();
Jeff Sharkey5b0e5202015-12-18 17:18:09 -07004014 pw.println("mConnector:");
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004015 pw.increaseIndent();
Robert Greenwalt470fd722012-01-18 12:51:15 -08004016 mConnector.dump(fd, pw, args);
Jeff Sharkey5aca2b82013-10-16 16:21:54 -07004017 pw.decreaseIndent();
Christopher Tate7265abe2014-11-21 13:54:45 -08004018
Christopher Tate7265abe2014-11-21 13:54:45 -08004019 pw.println();
Jeff Sharkey5b0e5202015-12-18 17:18:09 -07004020 pw.println("mCryptConnector:");
4021 pw.increaseIndent();
4022 mCryptConnector.dump(fd, pw, args);
4023 pw.decreaseIndent();
4024
4025 pw.println();
Christopher Tate7265abe2014-11-21 13:54:45 -08004026 pw.print("Last maintenance: ");
Jeff Sharkeye8a4b662015-06-27 15:43:45 -07004027 pw.println(TimeUtils.formatForLogging(mLastMaintenance));
Kenny Root38cf8862010-09-26 14:18:51 -07004028 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004029
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07004030 /** {@inheritDoc} */
Jeff Sharkey48877892015-03-18 11:27:19 -07004031 @Override
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07004032 public void monitor() {
4033 if (mConnector != null) {
4034 mConnector.monitor();
4035 }
Paul Lawrence1c62cbb2015-06-03 14:14:52 -07004036 if (mCryptConnector != null) {
4037 mCryptConnector.monitor();
4038 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07004039 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07004040
Sudheer Shanka2250d562016-11-07 15:41:02 -08004041 private final class StorageManagerInternalImpl extends StorageManagerInternal {
Svet Ganov6ee871e2015-07-10 14:29:33 -07004042 // Not guarded by a lock.
4043 private final CopyOnWriteArrayList<ExternalStorageMountPolicy> mPolicies =
4044 new CopyOnWriteArrayList<>();
4045
4046 @Override
4047 public void addExternalStoragePolicy(ExternalStorageMountPolicy policy) {
4048 // No locking - CopyOnWriteArrayList
4049 mPolicies.add(policy);
4050 }
4051
4052 @Override
4053 public void onExternalStoragePolicyChanged(int uid, String packageName) {
4054 final int mountMode = getExternalStorageMountMode(uid, packageName);
4055 remountUidExternalStorage(uid, mountMode);
4056 }
4057
4058 @Override
4059 public int getExternalStorageMountMode(int uid, String packageName) {
4060 // No locking - CopyOnWriteArrayList
4061 int mountMode = Integer.MAX_VALUE;
4062 for (ExternalStorageMountPolicy policy : mPolicies) {
4063 final int policyMode = policy.getMountMode(uid, packageName);
4064 if (policyMode == Zygote.MOUNT_EXTERNAL_NONE) {
4065 return Zygote.MOUNT_EXTERNAL_NONE;
4066 }
4067 mountMode = Math.min(mountMode, policyMode);
4068 }
4069 if (mountMode == Integer.MAX_VALUE) {
4070 return Zygote.MOUNT_EXTERNAL_NONE;
4071 }
4072 return mountMode;
4073 }
4074
4075 public boolean hasExternalStorage(int uid, String packageName) {
Amith Yamasani2bd5cff2015-07-22 14:42:31 -07004076 // No need to check for system uid. This avoids a deadlock between
4077 // PackageManagerService and AppOpsService.
4078 if (uid == Process.SYSTEM_UID) {
4079 return true;
4080 }
Svet Ganov6ee871e2015-07-10 14:29:33 -07004081 // No locking - CopyOnWriteArrayList
4082 for (ExternalStorageMountPolicy policy : mPolicies) {
4083 final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
4084 if (!policyHasStorage) {
4085 return false;
4086 }
4087 }
4088 return true;
4089 }
4090 }
Jeff Sharkeyfa23c5a2011-08-09 21:44:24 -07004091}