Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a318c254 authored by Eric Biggers's avatar Eric Biggers Committed by Android (Google) Code Review
Browse files

Merge changes from topic "unencrypted-dirs-q" into qt-dev

* changes:
  [RESTRICT AUTOMERGE] Log to EventLog on prepareUserStorage failure
  [RESTRICT AUTOMERGE] Ignore errors preparing user storage for existing users
  [RESTRICT AUTOMERGE] UserDataPreparer: reboot to recovery for system user only
  [RESTRICT AUTOMERGE] UserDataPreparer: reboot to recovery if preparing user storage fails
  [RESTRICT AUTOMERGE] StorageManagerService: don't ignore failures to prepare user storage
  Check user unlocked before write to /data/system_ce/0/snapshots
parents 08f8988b 2f2e7d84
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -221,4 +221,12 @@ public abstract class UserManagerInternal {
     */
    public abstract boolean isSettingRestrictedForUser(String setting, int userId, String value,
            int callingUid);

    /**
     * Returns {@code true} if the system should ignore errors when preparing
     * the storage directories for the user with ID {@code userId}. This will
     * return {@code false} for all new users; it will only return {@code true}
     * for users that already existed on-disk from an older version of Android.
     */
    public abstract boolean shouldIgnorePrepareStorageErrors(int userId);
}
+15 −0
Original line number Diff line number Diff line
@@ -117,6 +117,7 @@ import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.DataUnit;
import android.util.EventLog;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -2848,7 +2849,21 @@ class StorageManagerService extends IStorageManager.Stub
        try {
            mVold.prepareUserStorage(volumeUuid, userId, serialNumber, flags);
        } catch (Exception e) {
            EventLog.writeEvent(0x534e4554, "224585613", -1, "");
            Slog.wtf(TAG, e);
            // Make sure to re-throw this exception; we must not ignore failure
            // to prepare the user storage as it could indicate that encryption
            // wasn't successfully set up.
            //
            // Very unfortunately, these errors need to be ignored for broken
            // users that already existed on-disk from older Android versions.
            UserManagerInternal umInternal = LocalServices.getService(UserManagerInternal.class);
            if (umInternal.shouldIgnorePrepareStorageErrors(userId)) {
                Slog.wtf(TAG, "ignoring error preparing storage for existing user " + userId
                        + "; device may be insecure!");
                return;
            }
            throw new RuntimeException(e);
        }
    }

+11 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.pm.UserInfo;
import android.os.Environment;
import android.os.FileUtils;
import android.os.RecoverySystem;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.os.SystemProperties;
@@ -115,6 +116,16 @@ class UserDataPreparer {
                // Try one last time; if we fail again we're really in trouble
                prepareUserDataLI(volumeUuid, userId, userSerial,
                    flags | StorageManager.FLAG_STORAGE_DE, false);
            } else {
                try {
                    Log.wtf(TAG, "prepareUserData failed for user " + userId, e);
                    if (userId == UserHandle.USER_SYSTEM) {
                        RecoverySystem.rebootPromptAndWipeUserData(mContext,
                                "prepareUserData failed for system user");
                    }
                } catch (IOException e2) {
                    throw new RuntimeException("error rebooting into recovery", e2);
                }
            }
        }
    }
+42 −0
Original line number Diff line number Diff line
@@ -180,6 +180,8 @@ public class UserManagerService extends IUserManager.Stub {
    private static final String TAG_SEED_ACCOUNT_OPTIONS = "seedAccountOptions";
    private static final String TAG_LAST_REQUEST_QUIET_MODE_ENABLED_CALL =
            "lastRequestQuietModeEnabledCall";
    private static final String TAG_IGNORE_PREPARE_STORAGE_ERRORS =
            "ignorePrepareStorageErrors";
    private static final String ATTR_KEY = "key";
    private static final String ATTR_VALUE_TYPE = "type";
    private static final String ATTR_MULTIPLE = "m";
@@ -278,6 +280,14 @@ public class UserManagerService extends IUserManager.Stub {

        private long mLastRequestQuietModeEnabledMillis;

        /**
         * {@code true} if the system should ignore errors when preparing the
         * storage directories for this user. This is {@code false} for all new
         * users; it will only be {@code true} for users that already existed
         * on-disk from an older version of Android.
         */
        private boolean mIgnorePrepareStorageErrors;

        void setLastRequestQuietModeEnabledMillis(long millis) {
            mLastRequestQuietModeEnabledMillis = millis;
        }
@@ -286,6 +296,14 @@ public class UserManagerService extends IUserManager.Stub {
            return mLastRequestQuietModeEnabledMillis;
        }

        boolean getIgnorePrepareStorageErrors() {
            return mIgnorePrepareStorageErrors;
        }

        void setIgnorePrepareStorageErrors() {
            mIgnorePrepareStorageErrors = true;
        }

        void clearSeedAccountData() {
            seedAccountName = null;
            seedAccountType = null;
@@ -2380,6 +2398,10 @@ public class UserManagerService extends IUserManager.Stub {
            serializer.endTag(/* namespace */ null, TAG_LAST_REQUEST_QUIET_MODE_ENABLED_CALL);
        }

        serializer.startTag(/* namespace */ null, TAG_IGNORE_PREPARE_STORAGE_ERRORS);
        serializer.text(String.valueOf(userData.getIgnorePrepareStorageErrors()));
        serializer.endTag(/* namespace */ null, TAG_IGNORE_PREPARE_STORAGE_ERRORS);

        serializer.endTag(null, TAG_USER);

        serializer.endDocument();
@@ -2488,6 +2510,7 @@ public class UserManagerService extends IUserManager.Stub {
        Bundle baseRestrictions = null;
        Bundle localRestrictions = null;
        Bundle globalRestrictions = null;
        boolean ignorePrepareStorageErrors = true; // default is true for old users

        XmlPullParser parser = Xml.newPullParser();
        parser.setInput(is, StandardCharsets.UTF_8.name());
@@ -2566,6 +2589,11 @@ public class UserManagerService extends IUserManager.Stub {
                    if (type == XmlPullParser.TEXT) {
                        lastRequestQuietModeEnabledTimestamp = Long.parseLong(parser.getText());
                    }
                } else if (TAG_IGNORE_PREPARE_STORAGE_ERRORS.equals(tag)) {
                    type = parser.next();
                    if (type == XmlPullParser.TEXT) {
                        ignorePrepareStorageErrors = Boolean.parseBoolean(parser.getText());
                    }
                }
            }
        }
@@ -2591,6 +2619,9 @@ public class UserManagerService extends IUserManager.Stub {
        userData.persistSeedData = persistSeedData;
        userData.seedAccountOptions = seedAccountOptions;
        userData.setLastRequestQuietModeEnabledMillis(lastRequestQuietModeEnabledTimestamp);
        if (ignorePrepareStorageErrors) {
            userData.setIgnorePrepareStorageErrors();
        }

        synchronized (mRestrictionsLock) {
            if (baseRestrictions != null) {
@@ -3767,6 +3798,9 @@ public class UserManagerService extends IUserManager.Stub {
                            pw.println();
                        }
                    }

                    pw.println("    Ignore errors preparing storage: "
                            + userData.getIgnorePrepareStorageErrors());
                }
            }
            pw.println();
@@ -4111,6 +4145,14 @@ public class UserManagerService extends IUserManager.Stub {
            return UserRestrictionsUtils.isSettingRestrictedForUser(mContext, setting, userId,
                    value, callingUid);
        }

        @Override
        public boolean shouldIgnorePrepareStorageErrors(int userId) {
            synchronized (mUsersLock) {
                UserData userData = mUsers.get(userId);
                return userData != null && userData.getIgnorePrepareStorageErrors();
            }
        }
    }

    /* Remove all the users except of the system one. */
+30 −4
Original line number Diff line number Diff line
@@ -28,12 +28,14 @@ import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.os.Process;
import android.os.SystemClock;
import android.os.UserManagerInternal;
import android.util.ArraySet;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.AtomicFile;
import com.android.server.LocalServices;
import com.android.server.wm.nano.WindowManagerProtos.TaskSnapshotProto;

import java.io.File;
@@ -74,6 +76,7 @@ class TaskSnapshotPersister {
    private final Object mLock = new Object();
    private final DirectoryResolver mDirectoryResolver;
    private final float mReducedScale;
    private final UserManagerInternal mUserManagerInternal;

    /**
     * The list of ids of the tasks that have been persisted since {@link #removeObsoleteFiles} was
@@ -84,6 +87,9 @@ class TaskSnapshotPersister {

    TaskSnapshotPersister(WindowManagerService service, DirectoryResolver resolver) {
        mDirectoryResolver = resolver;

        mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);

        if (service.mLowRamTaskSnapshotsAndRecents) {
            // Use very low res snapshots if we are using Go version of recents.
            mReducedScale = LOW_RAM_RECENTS_REDUCED_SCALE;
@@ -172,7 +178,7 @@ class TaskSnapshotPersister {
                    return;
                }
            }
            SystemClock.sleep(100);
            SystemClock.sleep(DELAY_MS);
        }
    }

@@ -218,7 +224,7 @@ class TaskSnapshotPersister {

    private boolean createDirectory(int userId) {
        final File dir = getDirectory(userId);
        return dir.exists() || dir.mkdirs();
        return dir.exists() || dir.mkdir();
    }

    private void deleteSnapshot(int taskId, int userId) {
@@ -243,18 +249,26 @@ class TaskSnapshotPersister {
            android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
            while (true) {
                WriteQueueItem next;
                boolean isReadyToWrite = false;
                synchronized (mLock) {
                    if (mPaused) {
                        next = null;
                    } else {
                        next = mWriteQueue.poll();
                        if (next != null) {
                            if (next.isReady()) {
                                isReadyToWrite = true;
                                next.onDequeuedLocked();
                            } else {
                                mWriteQueue.addLast(next);
                            }
                        }
                    }
                }
                if (next != null) {
                    if (isReadyToWrite) {
                        next.write();
                    }
                    SystemClock.sleep(DELAY_MS);
                }
                synchronized (mLock) {
@@ -274,6 +288,13 @@ class TaskSnapshotPersister {
    };

    private abstract class WriteQueueItem {
        /**
         * @return {@code true} if item is ready to have {@link WriteQueueItem#write} called
         */
        boolean isReady() {
            return true;
        }

        abstract void write();

        /**
@@ -312,6 +333,11 @@ class TaskSnapshotPersister {
            mStoreQueueItems.remove(this);
        }

        @Override
        boolean isReady() {
            return mUserManagerInternal.isUserUnlocked(mUserId);
        }

        @Override
        void write() {
            if (!createDirectory(mUserId)) {
Loading