From a65e6491e4aa90611045ecf696db4bf3328d09bc Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 21 Jun 2017 13:45:11 -0600 Subject: Progress towards FBE and adoptable storage. Offer to adopt storage devices on FBE devices, but keep it guarded behind a system property for now, since we still need to work out key storage details. Verify that all users are unlocked before moving apps or shared storage. We only need them to be unlocked; we don't need them to be actually running. Have PackageManager dump the set of volumes that it's finished scanning and loading, since otherwise CTS can get excited and race too far ahead of it. Add a specific error code to communicate that users are locked. Test: cts-tradefed run commandAndExit cts-dev --abi armeabi-v7a -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AdoptableHostTest Bug: 37436961, 29923055, 25861755, 30230655 Change-Id: I749dc3d8148e1a95d8bc4be56665253ef826d3fe --- core/java/android/app/ContextImpl.java | 13 ++----- core/java/android/content/pm/PackageManager.java | 3 ++ core/java/android/os/storage/StorageManager.java | 2 + .../com/android/server/StorageManagerService.java | 18 ++++++++- .../android/server/pm/PackageManagerService.java | 44 ++++++++++++++++++++-- .../android/server/trust/TrustManagerService.java | 2 +- 6 files changed, 66 insertions(+), 16 deletions(-) diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index a040520ffb9f..232d42e463f8 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -63,6 +63,7 @@ import android.os.ServiceManager; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; +import android.os.UserManager; import android.os.storage.IStorageManager; import android.os.storage.StorageManager; import android.system.ErrnoException; @@ -370,13 +371,6 @@ class ContextImpl extends Context { return getSharedPreferences(file, mode); } - private boolean isBuggy() { - // STOPSHIP: fix buggy apps - if (SystemProperties.getBoolean("fw.ignore_buggy", false)) return false; - if ("com.google.android.tts".equals(getApplicationInfo().packageName)) return true; - return false; - } - @Override public SharedPreferences getSharedPreferences(File file, int mode) { SharedPreferencesImpl sp; @@ -387,9 +381,8 @@ class ContextImpl extends Context { checkMode(mode); if (getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.O) { if (isCredentialProtectedStorage() - && !getSystemService(StorageManager.class).isUserKeyUnlocked( - UserHandle.myUserId()) - && !isBuggy()) { + && !getSystemService(UserManager.class) + .isUserUnlockingOrUnlocked(UserHandle.myUserId())) { throw new IllegalStateException("SharedPreferences in credential encrypted " + "storage are not available until after user is unlocked"); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 6bc7d42a14b2..712d37f00bfb 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1490,6 +1490,9 @@ public abstract class PackageManager { */ public static final int MOVE_FAILED_3RD_PARTY_NOT_ALLOWED_ON_INTERNAL = -9; + /** @hide */ + public static final int MOVE_FAILED_LOCKED_USER = -10; + /** * Flag parameter for {@link #movePackage} to indicate that * the package should be moved to internal storage if its diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index f2aa113ea28e..71f5ff775ea0 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -118,6 +118,8 @@ public class StorageManager { public static final String PROP_SDCARDFS = "persist.sys.sdcardfs"; /** {@hide} */ public static final String PROP_VIRTUAL_DISK = "persist.sys.virtual_disk"; + /** {@hide} */ + public static final String PROP_ADOPTABLE_FBE = "persist.sys.adoptable_fbe"; /** {@hide} */ public static final String UUID_PRIVATE_INTERNAL = null; diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index f718e803a973..aa2ce1ce3857 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -108,6 +108,7 @@ import com.android.internal.util.Preconditions; import com.android.internal.widget.LockPatternUtils; import com.android.server.NativeDaemonConnector.Command; import com.android.server.NativeDaemonConnector.SensitiveArg; +import com.android.server.pm.PackageManagerException; import com.android.server.pm.PackageManagerService; import com.android.server.storage.AppFuseBridge; @@ -1078,7 +1079,8 @@ class StorageManagerService extends IStorageManager.Stub flags |= DiskInfo.FLAG_ADOPTABLE; } // Adoptable storage isn't currently supported on FBE devices - if (StorageManager.isFileEncryptedNativeOnly()) { + if (StorageManager.isFileEncryptedNativeOnly() + && !SystemProperties.getBoolean(StorageManager.PROP_ADOPTABLE_FBE, false)) { flags &= ~DiskInfo.FLAG_ADOPTABLE; } mDisks.put(id, new DiskInfo(id, flags)); @@ -2045,7 +2047,8 @@ class StorageManagerService extends IStorageManager.Stub } if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) { - if (StorageManager.isFileEncryptedNativeOnly()) { + if (StorageManager.isFileEncryptedNativeOnly() + && !SystemProperties.getBoolean(StorageManager.PROP_ADOPTABLE_FBE, false)) { throw new IllegalStateException( "Adoptable storage not available on device with native FBE"); } @@ -2121,6 +2124,17 @@ class StorageManagerService extends IStorageManager.Stub mMoveCallback = callback; mMoveTargetUuid = volumeUuid; + // We need all the users unlocked to move their primary storage + final List users = mContext.getSystemService(UserManager.class).getUsers(); + for (UserInfo user : users) { + if (StorageManager.isFileEncryptedNativeOrEmulated() + && !isUserKeyUnlocked(user.id)) { + Slog.w(TAG, "Failing move due to locked user " + user.id); + onMoveStatusLocked(PackageManager.MOVE_FAILED_LOCKED_USER); + return; + } + } + // When moving to/from primary physical volume, we probably just nuked // the current storage location, so we have nothing to move. if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, mPrimaryStorageUuid) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 2ac7e5043518..eb532ff4a983 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -58,7 +58,6 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE import static android.content.pm.PackageManager.INSTALL_FORWARD_LOCK; import static android.content.pm.PackageManager.INSTALL_INTERNAL; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; @@ -78,6 +77,7 @@ import static android.content.pm.PackageManager.MOVE_FAILED_3RD_PARTY_NOT_ALLOWE import static android.content.pm.PackageManager.MOVE_FAILED_DEVICE_ADMIN; import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST; import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR; +import static android.content.pm.PackageManager.MOVE_FAILED_LOCKED_USER; import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING; import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE; import static android.content.pm.PackageManager.PERMISSION_DENIED; @@ -87,6 +87,7 @@ import static android.content.pm.PackageParser.isApkFile; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.system.OsConstants.O_CREAT; import static android.system.OsConstants.O_RDWR; + import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE; import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT; import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME; @@ -102,6 +103,7 @@ import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefa import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_FAILURE; import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS; import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED; + import static dalvik.system.DexFile.getNonProfileGuidedCompilerFilter; import android.Manifest; @@ -130,6 +132,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.AppsQueryHelper; import android.content.pm.AuxiliaryResolveInfo; import android.content.pm.ChangedPackages; +import android.content.pm.ComponentInfo; import android.content.pm.FallbackCategoryProvider; import android.content.pm.FeatureInfo; import android.content.pm.IDexModuleRegisterCallback; @@ -724,6 +727,9 @@ public class PackageManagerService extends IPackageManager.Stub final ProtectedPackages mProtectedPackages; + @GuardedBy("mLoadedVolumes") + final ArraySet mLoadedVolumes = new ArraySet<>(); + boolean mFirstBoot; PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy; @@ -21675,6 +21681,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); public static final int DUMP_DEXOPT = 1 << 20; public static final int DUMP_COMPILER_STATS = 1 << 21; public static final int DUMP_CHANGES = 1 << 22; + public static final int DUMP_VOLUMES = 1 << 23; public static final int OPTION_SHOW_FILTERS = 1 << 0; @@ -21914,6 +21921,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); dumpState.setDump(DumpState.DUMP_INSTALLS); } else if ("frozen".equals(cmd)) { dumpState.setDump(DumpState.DUMP_FROZEN); + } else if ("volumes".equals(cmd)) { + dumpState.setDump(DumpState.DUMP_VOLUMES); } else if ("dexopt".equals(cmd)) { dumpState.setDump(DumpState.DUMP_DEXOPT); } else if ("compiler-stats".equals(cmd)) { @@ -22298,6 +22307,23 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); ipw.decreaseIndent(); } + if (!checkin && dumpState.isDumping(DumpState.DUMP_VOLUMES) && packageName == null) { + if (dumpState.onTitlePrinted()) pw.println(); + + final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); + ipw.println(); + ipw.println("Loaded volumes:"); + ipw.increaseIndent(); + if (mLoadedVolumes.size() == 0) { + ipw.println("(none)"); + } else { + for (int i = 0; i < mLoadedVolumes.size(); i++) { + ipw.println(mLoadedVolumes.valueAt(i)); + } + } + ipw.decreaseIndent(); + } + if (!checkin && dumpState.isDumping(DumpState.DUMP_DEXOPT)) { if (dumpState.onTitlePrinted()) pw.println(); dumpDexoptStateLPr(pw, packageName); @@ -23014,6 +23040,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); if (DEBUG_INSTALL) Slog.d(TAG, "Loaded packages " + loaded); sendResourcesChangedBroadcast(true, false, loaded, null); + mLoadedVolumes.add(vol.getId()); } private void unloadPrivatePackages(final VolumeInfo vol) { @@ -23065,6 +23092,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); if (DEBUG_INSTALL) Slog.d(TAG, "Unloaded packages " + unloaded); sendResourcesChangedBroadcast(false, false, unloaded, null); + mLoadedVolumes.remove(vol.getId()); // Try very hard to release any references to this path so we don't risk // the system server being killed due to open FDs @@ -23608,8 +23636,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); movePackageInternal(packageName, volumeUuid, moveId, callingUid, user); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to move " + packageName, e); - mMoveCallbacks.notifyStatusChanged(moveId, - PackageManager.MOVE_FAILED_INTERNAL_ERROR); + mMoveCallbacks.notifyStatusChanged(moveId, e.error); } } }); @@ -23732,6 +23759,17 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); measurePath = Environment.getDataAppDirectory(volumeUuid); } + // If we're moving app data around, we need all the users unlocked + if (moveCompleteApp) { + for (int userId : installedUserIds) { + if (StorageManager.isFileEncryptedNativeOrEmulated() + && !StorageManager.isUserKeyUnlocked(userId)) { + throw new PackageManagerException(MOVE_FAILED_LOCKED_USER, + "User " + userId + " must be unlocked"); + } + } + } + final PackageStats stats = new PackageStats(null, -1); synchronized (mInstaller) { for (int userId : installedUserIds) { diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 35e4e58c92cf..c07bd8e3a2d3 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -345,7 +345,7 @@ public class TrustManagerService extends SystemService { + "of user " + userInfo.id + "can unlock user profile."); } - if (!StorageManager.isUserKeyUnlocked(userInfo.id) + if (!mUserManager.isUserUnlockingOrUnlocked(userInfo.id) && !directUnlock) { if (DEBUG) Slog.d(TAG, "refreshAgentList: skipping user " + userInfo.id + "'s trust agent " + name + ": FBE still locked and " -- cgit v1.2.3-59-g8ed1b