Loading services/core/java/com/android/server/pm/UserManagerService.java +177 −117 Original line number Diff line number Diff line Loading @@ -278,6 +278,7 @@ public class UserManagerService extends IUserManager.Stub { private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms static final int WRITE_USER_MSG = 1; static final int WRITE_USER_LIST_MSG = 2; static final int WRITE_USER_DELAY = 2*1000; // 2 seconds private static final long BOOT_USER_SET_TIMEOUT_MS = 300_000; Loading Loading @@ -321,7 +322,6 @@ public class UserManagerService extends IUserManager.Stub { private final Handler mHandler; private final File mUsersDir; @GuardedBy("mPackagesLock") private final File mUserListFile; private final IBinder mUserRestrictionToken = new Binder(); Loading Loading @@ -3623,17 +3623,33 @@ public class UserManagerService extends IUserManager.Stub { mUpdatingSystemUserMode = true; } private ResilientAtomicFile getUserListFile() { File tempBackup = new File(mUserListFile.getParent(), mUserListFile.getName() + ".backup"); File reserveCopy = new File(mUserListFile.getParent(), mUserListFile.getName() + ".reservecopy"); int fileMode = FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH; return new ResilientAtomicFile(mUserListFile, tempBackup, reserveCopy, fileMode, "user list", (priority, msg) -> { Slog.e(LOG_TAG, msg); // Something went wrong, schedule full rewrite. scheduleWriteUserList(); }); } @GuardedBy({"mPackagesLock"}) private void readUserListLP() { if (!mUserListFile.exists()) { try (ResilientAtomicFile file = getUserListFile()) { FileInputStream fin = null; try { fin = file.openRead(); if (fin == null) { Slog.e(LOG_TAG, "userlist.xml not found, fallback to single user"); fallbackToSingleUserLP(); return; } FileInputStream fis = null; AtomicFile userListFile = new AtomicFile(mUserListFile); try { fis = userListFile.openRead(); final TypedXmlPullParser parser = Xml.resolvePullParser(fis); final TypedXmlPullParser parser = Xml.resolvePullParser(fin); int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { Loading Loading @@ -3690,10 +3706,12 @@ public class UserManagerService extends IUserManager.Stub { updateUserIds(); upgradeIfNecessaryLP(); } catch (IOException | XmlPullParserException e) { fallbackToSingleUserLP(); } finally { IoUtils.closeQuietly(fis); } catch (Exception e) { // Remove corrupted file and retry. file.failRead(fin, e); readUserListLP(); return; } } synchronized (mUsersLock) { Loading Loading @@ -4099,6 +4117,18 @@ public class UserManagerService extends IUserManager.Stub { } } private void scheduleWriteUserList() { if (DBG) { debug("scheduleWriteUserList"); } // No need to wrap it within a lock -- worst case, we'll just post the same message // twice. if (!mHandler.hasMessages(WRITE_USER_LIST_MSG)) { Message msg = mHandler.obtainMessage(WRITE_USER_LIST_MSG); mHandler.sendMessageDelayed(msg, WRITE_USER_DELAY); } } private void scheduleWriteUser(UserData userData) { if (DBG) { debug("scheduleWriteUser"); Loading @@ -4111,13 +4141,29 @@ public class UserManagerService extends IUserManager.Stub { } } private ResilientAtomicFile getUserFile(int userId) { File file = new File(mUsersDir, userId + XML_SUFFIX); File tempBackup = new File(mUsersDir, userId + XML_SUFFIX + ".backup"); File reserveCopy = new File(mUsersDir, userId + XML_SUFFIX + ".reservecopy"); int fileMode = FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH; return new ResilientAtomicFile(file, tempBackup, reserveCopy, fileMode, "user info", (priority, msg) -> { Slog.e(LOG_TAG, msg); // Something went wrong, schedule full rewrite. UserData userData = getUserDataNoChecks(userId); if (userData != null) { scheduleWriteUser(userData); } }); } @GuardedBy({"mPackagesLock"}) private void writeUserLP(UserData userData) { if (DBG) { debug("writeUserLP " + userData); } try (ResilientAtomicFile userFile = getUserFile(userData.info.id)) { FileOutputStream fos = null; AtomicFile userFile = new AtomicFile(new File(mUsersDir, userData.info.id + XML_SUFFIX)); try { fos = userFile.startWrite(); writeUserLP(userData, fos); Loading @@ -4127,6 +4173,7 @@ public class UserManagerService extends IUserManager.Stub { userFile.failWrite(fos); } } } /* * Writes the user file in this format: Loading Loading @@ -4253,13 +4300,16 @@ public class UserManagerService extends IUserManager.Stub { if (DBG) { debug("writeUserList"); } try (ResilientAtomicFile file = getUserListFile()) { FileOutputStream fos = null; AtomicFile userListFile = new AtomicFile(mUserListFile); try { fos = userListFile.startWrite(); fos = file.startWrite(); final TypedXmlSerializer serializer = Xml.resolveSerializer(fos); serializer.startDocument(null, true); serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); serializer.startTag(null, TAG_USERS); serializer.attributeInt(null, ATTR_NEXT_SERIAL_NO, mNextSerialNumber); Loading Loading @@ -4289,29 +4339,32 @@ public class UserManagerService extends IUserManager.Stub { serializer.endTag(null, TAG_USERS); serializer.endDocument(); userListFile.finishWrite(fos); file.finishWrite(fos); } catch (Exception e) { userListFile.failWrite(fos); Slog.e(LOG_TAG, "Error writing user list"); Slog.e(LOG_TAG, "Error writing user list", e); file.failWrite(fos); } } } @GuardedBy({"mPackagesLock"}) private UserData readUserLP(int id) { try (ResilientAtomicFile file = getUserFile(id)) { FileInputStream fis = null; try { AtomicFile userFile = new AtomicFile(new File(mUsersDir, Integer.toString(id) + XML_SUFFIX)); fis = userFile.openRead(); fis = file.openRead(); if (fis == null) { Slog.e(LOG_TAG, "User info not found, returning null, user id: " + id); return null; } return readUserLP(id, fis); } catch (IOException ioe) { Slog.e(LOG_TAG, "Error reading user list"); } catch (XmlPullParserException pe) { Slog.e(LOG_TAG, "Error reading user list"); } finally { IoUtils.closeQuietly(fis); } catch (Exception e) { // Remove corrupted file and retry. Slog.e(LOG_TAG, "Error reading user info, user id: " + id); file.failRead(fis, e); return readUserLP(id); } } return null; } @GuardedBy({"mPackagesLock"}) Loading Loading @@ -5805,9 +5858,8 @@ public class UserManagerService extends IUserManager.Stub { synchronized (mPackagesLock) { writeUserListLP(); } // Remove user file AtomicFile userFile = new AtomicFile(new File(mUsersDir, userId + XML_SUFFIX)); userFile.delete(); // Remove user file(s) getUserFile(userId).delete(); updateUserIds(); if (RELEASE_DELETED_USER_ID) { synchronized (mUsersLock) { Loading Loading @@ -6770,6 +6822,13 @@ public class UserManagerService extends IUserManager.Stub { @Override public void handleMessage(Message msg) { switch (msg.what) { case WRITE_USER_LIST_MSG: { removeMessages(WRITE_USER_LIST_MSG); synchronized (mPackagesLock) { writeUserListLP(); } break; } case WRITE_USER_MSG: removeMessages(WRITE_USER_MSG, msg.obj); synchronized (mPackagesLock) { Loading @@ -6782,6 +6841,7 @@ public class UserManagerService extends IUserManager.Stub { + ", it was probably removed before handler could handle it"); } } break; } } } Loading Loading
services/core/java/com/android/server/pm/UserManagerService.java +177 −117 Original line number Diff line number Diff line Loading @@ -278,6 +278,7 @@ public class UserManagerService extends IUserManager.Stub { private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms static final int WRITE_USER_MSG = 1; static final int WRITE_USER_LIST_MSG = 2; static final int WRITE_USER_DELAY = 2*1000; // 2 seconds private static final long BOOT_USER_SET_TIMEOUT_MS = 300_000; Loading Loading @@ -321,7 +322,6 @@ public class UserManagerService extends IUserManager.Stub { private final Handler mHandler; private final File mUsersDir; @GuardedBy("mPackagesLock") private final File mUserListFile; private final IBinder mUserRestrictionToken = new Binder(); Loading Loading @@ -3623,17 +3623,33 @@ public class UserManagerService extends IUserManager.Stub { mUpdatingSystemUserMode = true; } private ResilientAtomicFile getUserListFile() { File tempBackup = new File(mUserListFile.getParent(), mUserListFile.getName() + ".backup"); File reserveCopy = new File(mUserListFile.getParent(), mUserListFile.getName() + ".reservecopy"); int fileMode = FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH; return new ResilientAtomicFile(mUserListFile, tempBackup, reserveCopy, fileMode, "user list", (priority, msg) -> { Slog.e(LOG_TAG, msg); // Something went wrong, schedule full rewrite. scheduleWriteUserList(); }); } @GuardedBy({"mPackagesLock"}) private void readUserListLP() { if (!mUserListFile.exists()) { try (ResilientAtomicFile file = getUserListFile()) { FileInputStream fin = null; try { fin = file.openRead(); if (fin == null) { Slog.e(LOG_TAG, "userlist.xml not found, fallback to single user"); fallbackToSingleUserLP(); return; } FileInputStream fis = null; AtomicFile userListFile = new AtomicFile(mUserListFile); try { fis = userListFile.openRead(); final TypedXmlPullParser parser = Xml.resolvePullParser(fis); final TypedXmlPullParser parser = Xml.resolvePullParser(fin); int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { Loading Loading @@ -3690,10 +3706,12 @@ public class UserManagerService extends IUserManager.Stub { updateUserIds(); upgradeIfNecessaryLP(); } catch (IOException | XmlPullParserException e) { fallbackToSingleUserLP(); } finally { IoUtils.closeQuietly(fis); } catch (Exception e) { // Remove corrupted file and retry. file.failRead(fin, e); readUserListLP(); return; } } synchronized (mUsersLock) { Loading Loading @@ -4099,6 +4117,18 @@ public class UserManagerService extends IUserManager.Stub { } } private void scheduleWriteUserList() { if (DBG) { debug("scheduleWriteUserList"); } // No need to wrap it within a lock -- worst case, we'll just post the same message // twice. if (!mHandler.hasMessages(WRITE_USER_LIST_MSG)) { Message msg = mHandler.obtainMessage(WRITE_USER_LIST_MSG); mHandler.sendMessageDelayed(msg, WRITE_USER_DELAY); } } private void scheduleWriteUser(UserData userData) { if (DBG) { debug("scheduleWriteUser"); Loading @@ -4111,13 +4141,29 @@ public class UserManagerService extends IUserManager.Stub { } } private ResilientAtomicFile getUserFile(int userId) { File file = new File(mUsersDir, userId + XML_SUFFIX); File tempBackup = new File(mUsersDir, userId + XML_SUFFIX + ".backup"); File reserveCopy = new File(mUsersDir, userId + XML_SUFFIX + ".reservecopy"); int fileMode = FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH; return new ResilientAtomicFile(file, tempBackup, reserveCopy, fileMode, "user info", (priority, msg) -> { Slog.e(LOG_TAG, msg); // Something went wrong, schedule full rewrite. UserData userData = getUserDataNoChecks(userId); if (userData != null) { scheduleWriteUser(userData); } }); } @GuardedBy({"mPackagesLock"}) private void writeUserLP(UserData userData) { if (DBG) { debug("writeUserLP " + userData); } try (ResilientAtomicFile userFile = getUserFile(userData.info.id)) { FileOutputStream fos = null; AtomicFile userFile = new AtomicFile(new File(mUsersDir, userData.info.id + XML_SUFFIX)); try { fos = userFile.startWrite(); writeUserLP(userData, fos); Loading @@ -4127,6 +4173,7 @@ public class UserManagerService extends IUserManager.Stub { userFile.failWrite(fos); } } } /* * Writes the user file in this format: Loading Loading @@ -4253,13 +4300,16 @@ public class UserManagerService extends IUserManager.Stub { if (DBG) { debug("writeUserList"); } try (ResilientAtomicFile file = getUserListFile()) { FileOutputStream fos = null; AtomicFile userListFile = new AtomicFile(mUserListFile); try { fos = userListFile.startWrite(); fos = file.startWrite(); final TypedXmlSerializer serializer = Xml.resolveSerializer(fos); serializer.startDocument(null, true); serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); serializer.startTag(null, TAG_USERS); serializer.attributeInt(null, ATTR_NEXT_SERIAL_NO, mNextSerialNumber); Loading Loading @@ -4289,29 +4339,32 @@ public class UserManagerService extends IUserManager.Stub { serializer.endTag(null, TAG_USERS); serializer.endDocument(); userListFile.finishWrite(fos); file.finishWrite(fos); } catch (Exception e) { userListFile.failWrite(fos); Slog.e(LOG_TAG, "Error writing user list"); Slog.e(LOG_TAG, "Error writing user list", e); file.failWrite(fos); } } } @GuardedBy({"mPackagesLock"}) private UserData readUserLP(int id) { try (ResilientAtomicFile file = getUserFile(id)) { FileInputStream fis = null; try { AtomicFile userFile = new AtomicFile(new File(mUsersDir, Integer.toString(id) + XML_SUFFIX)); fis = userFile.openRead(); fis = file.openRead(); if (fis == null) { Slog.e(LOG_TAG, "User info not found, returning null, user id: " + id); return null; } return readUserLP(id, fis); } catch (IOException ioe) { Slog.e(LOG_TAG, "Error reading user list"); } catch (XmlPullParserException pe) { Slog.e(LOG_TAG, "Error reading user list"); } finally { IoUtils.closeQuietly(fis); } catch (Exception e) { // Remove corrupted file and retry. Slog.e(LOG_TAG, "Error reading user info, user id: " + id); file.failRead(fis, e); return readUserLP(id); } } return null; } @GuardedBy({"mPackagesLock"}) Loading Loading @@ -5805,9 +5858,8 @@ public class UserManagerService extends IUserManager.Stub { synchronized (mPackagesLock) { writeUserListLP(); } // Remove user file AtomicFile userFile = new AtomicFile(new File(mUsersDir, userId + XML_SUFFIX)); userFile.delete(); // Remove user file(s) getUserFile(userId).delete(); updateUserIds(); if (RELEASE_DELETED_USER_ID) { synchronized (mUsersLock) { Loading Loading @@ -6770,6 +6822,13 @@ public class UserManagerService extends IUserManager.Stub { @Override public void handleMessage(Message msg) { switch (msg.what) { case WRITE_USER_LIST_MSG: { removeMessages(WRITE_USER_LIST_MSG); synchronized (mPackagesLock) { writeUserListLP(); } break; } case WRITE_USER_MSG: removeMessages(WRITE_USER_MSG, msg.obj); synchronized (mPackagesLock) { Loading @@ -6782,6 +6841,7 @@ public class UserManagerService extends IUserManager.Stub { + ", it was probably removed before handler could handle it"); } } break; } } } Loading