From bc215de99298ca59119319ac5bf7285bc3c789a6 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Thu, 5 Dec 2019 15:23:16 -0800 Subject: [PATCH] Make AccountManagerService more resilient to database corruption. Currently, if a user accounts database is corrupted, the system will crash and boot loop. This CL mitigates the issue by removing the user instead. Bug: 145710595 Test: adb shell chmod 000 /data/system_de/10/accounts_de.db && adb reboot Change-Id: I47916fde4577709a2555586b8dc94090605595bd (cherry picked from commit 8472b904ecef69ee12818fa1f69458875a58c8df) --- .../accounts/AccountManagerService.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 1432f57b4464a..0d2882216f08f 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -1289,6 +1289,33 @@ public class AccountManagerService } protected UserAccounts getUserAccounts(int userId) { + try { + return getUserAccountsNotChecked(userId); + } catch (RuntimeException e) { + if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { + // Let it go... + throw e; + } + // User accounts database is corrupted, we must wipe out the whole user, otherwise the + // system will crash indefinitely + Slog.wtf(TAG, "Removing user " + userId + " due to exception (" + e + ") reading its " + + "account database"); + if (userId == ActivityManager.getCurrentUser() && userId != UserHandle.USER_SYSTEM) { + Slog.i(TAG, "Switching to system user first"); + try { + ActivityManager.getService().switchUser(UserHandle.USER_SYSTEM); + } catch (RemoteException re) { + Slog.e(TAG, "Could not switch to " + UserHandle.USER_SYSTEM + ": " + re); + } + } + if (!getUserManager().removeUserEvenWhenDisallowed(userId)) { + Slog.e(TAG, "could not remove user " + userId); + } + throw e; + } + } + + private UserAccounts getUserAccountsNotChecked(int userId) { synchronized (mUsers) { UserAccounts accounts = mUsers.get(userId); boolean validateAccounts = false;