AccountManagerBackupHelper.java revision 5d09c998a03eea53218c3b3c40e20db1b7693c9c
15d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov/* 25d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * Copyright (C) 2016 The Android Open Source Project 35d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * 45d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * Licensed under the Apache License, Version 2.0 (the "License"); 55d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * you may not use this file except in compliance with the License. 65d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * You may obtain a copy of the License at 75d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * 85d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * http://www.apache.org/licenses/LICENSE-2.0 95d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * 105d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * Unless required by applicable law or agreed to in writing, software 115d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * distributed under the License is distributed on an "AS IS" BASIS, 125d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * See the License for the specific language governing permissions and 145d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * limitations under the License. 155d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov */ 165d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 175d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovpackage com.android.server.accounts; 185d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 195d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.accounts.Account; 205d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.accounts.AccountManager; 215d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.accounts.AccountManagerInternal; 225d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.annotation.IntRange; 235d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.annotation.NonNull; 245d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.content.pm.PackageInfo; 255d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.content.pm.PackageManager; 265d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.database.Cursor; 275d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.database.sqlite.SQLiteDatabase; 285d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.os.UserHandle; 295d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.text.TextUtils; 305d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.util.Log; 315d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.util.PackageUtils; 325d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.util.Xml; 335d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport com.android.internal.annotations.GuardedBy; 345d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport com.android.internal.content.PackageMonitor; 355d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport com.android.internal.util.FastXmlSerializer; 365d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport com.android.internal.util.XmlUtils; 375d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport org.xmlpull.v1.XmlPullParser; 385d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport org.xmlpull.v1.XmlPullParserException; 395d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport org.xmlpull.v1.XmlSerializer; 405d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 415d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport java.io.ByteArrayInputStream; 425d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport java.io.ByteArrayOutputStream; 435d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport java.io.IOException; 445d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport java.nio.charset.StandardCharsets; 455d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport java.util.ArrayList; 465d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport java.util.List; 475d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 485d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov/** 495d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * Helper class for backup and restore of account access grants. 505d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov */ 515d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovpublic final class AccountManagerBackupHelper { 525d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private static final String TAG = "AccountManagerBackupHelper"; 535d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 545d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private static final long PENDING_RESTORE_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour 555d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 565d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private static final String TAG_PERMISSIONS = "permissions"; 575d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private static final String TAG_PERMISSION = "permission"; 585d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private static final String ATTR_ACCOUNT_SHA_256 = "account-sha-256"; 595d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private static final String ATTR_PACKAGE = "package"; 605d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private static final String ATTR_DIGEST = "digest"; 615d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 625d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private static final String ACCOUNT_ACCESS_GRANTS = "" 635d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov + "SELECT " + AccountManagerService.ACCOUNTS_NAME + ", " 645d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov + AccountManagerService.GRANTS_GRANTEE_UID 655d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov + " FROM " + AccountManagerService.TABLE_ACCOUNTS 665d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov + ", " + AccountManagerService.TABLE_GRANTS 675d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov + " WHERE " + AccountManagerService.GRANTS_ACCOUNTS_ID 685d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov + "=" + AccountManagerService.ACCOUNTS_ID; 695d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 705d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final Object mLock = new Object(); 715d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 725d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final AccountManagerService mAccountManagerService; 735d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final AccountManagerInternal mAccountManagerInternal; 745d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 755d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov @GuardedBy("mLock") 765d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private List<PendingAppPermission> mRestorePendingAppPermissions; 775d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 785d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov @GuardedBy("mLock") 795d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private RestorePackageMonitor mRestorePackageMonitor; 805d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 815d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov @GuardedBy("mLock") 825d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private Runnable mRestoreCancelCommand; 835d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 845d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov public AccountManagerBackupHelper(AccountManagerService accountManagerService, 855d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov AccountManagerInternal accountManagerInternal) { 865d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mAccountManagerService = accountManagerService; 875d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mAccountManagerInternal = accountManagerInternal; 885d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 895d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 905d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final class PendingAppPermission { 915d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final @NonNull String accountDigest; 925d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final @NonNull String packageName; 935d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final @NonNull String certDigest; 945d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final @IntRange(from = 0) int userId; 955d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 965d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov public PendingAppPermission(String accountDigest, String packageName, 975d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov String certDigest, int userId) { 985d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov this.accountDigest = accountDigest; 995d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov this.packageName = packageName; 1005d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov this.certDigest = certDigest; 1015d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov this.userId = userId; 1025d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1035d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 1045d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov public boolean apply(PackageManager packageManager) { 1055d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov Account account = null; 1065d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov AccountManagerService.UserAccounts accounts = mAccountManagerService 1075d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov .getUserAccounts(userId); 1085d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov synchronized (accounts.cacheLock) { 1095d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov for (Account[] accountsPerType : accounts.accountCache.values()) { 1105d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov for (Account accountPerType : accountsPerType) { 1115d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (accountDigest.equals(PackageUtils.computeSha256Digest( 1125d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov accountPerType.name.getBytes()))) { 1135d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov account = accountPerType; 1145d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov break; 1155d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1165d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1175d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (account != null) { 1185d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov break; 1195d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1205d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1215d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1225d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (account == null) { 1235d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov return false; 1245d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1255d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final PackageInfo packageInfo; 1265d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov try { 1275d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov packageInfo = packageManager.getPackageInfoAsUser(packageName, 1285d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov PackageManager.GET_SIGNATURES, userId); 1295d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } catch (PackageManager.NameNotFoundException e) { 1305d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov return false; 1315d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1325d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov String currentCertDigest = PackageUtils.computeCertSha256Digest( 1335d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov packageInfo.signatures[0]); 1345d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (!certDigest.equals(currentCertDigest)) { 1355d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov return false; 1365d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1375d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final int uid = packageInfo.applicationInfo.uid; 1385d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (!mAccountManagerInternal.hasAccountAccess(account, uid)) { 1395d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mAccountManagerService.grantAppPermission(account, 1405d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid); 1415d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1425d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov return true; 1435d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1445d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1455d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 1465d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov public byte[] backupAccountAccessPermissions(int userId) { 1475d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final AccountManagerService.UserAccounts accounts = mAccountManagerService 1485d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov .getUserAccounts(userId); 1495d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov synchronized (accounts.cacheLock) { 1505d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov SQLiteDatabase db = accounts.openHelper.getReadableDatabase(); 1515d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov try ( 1525d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov Cursor cursor = db.rawQuery(ACCOUNT_ACCESS_GRANTS, null); 1535d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov ) { 1545d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (cursor == null || !cursor.moveToFirst()) { 1555d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov return null; 1565d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1575d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 1585d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final int nameColumnIdx = cursor.getColumnIndex( 1595d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov AccountManagerService.ACCOUNTS_NAME); 1605d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final int uidColumnIdx = cursor.getColumnIndex( 1615d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov AccountManagerService.GRANTS_GRANTEE_UID); 1625d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 1635d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); 1645d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov try { 1655d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final XmlSerializer serializer = new FastXmlSerializer(); 1665d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov serializer.setOutput(dataStream, StandardCharsets.UTF_8.name()); 1675d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov serializer.startDocument(null, true); 1685d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov serializer.startTag(null, TAG_PERMISSIONS); 1695d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 1705d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov PackageManager packageManager = mAccountManagerService.mContext 1715d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov .getPackageManager(); 1725d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 1735d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov do { 1745d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final String accountName = cursor.getString(nameColumnIdx); 1755d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final int uid = cursor.getInt(uidColumnIdx); 1765d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 1775d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final String[] packageNames = packageManager.getPackagesForUid(uid); 1785d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (packageNames == null) { 1795d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov continue; 1805d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1815d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 1825d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov for (String packageName : packageNames) { 1835d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov String digest = PackageUtils.computePackageCertSha256Digest( 1845d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov packageManager, packageName, userId); 1855d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (digest != null) { 1865d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov serializer.startTag(null, TAG_PERMISSION); 1875d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov serializer.attribute(null, ATTR_ACCOUNT_SHA_256, 1885d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov PackageUtils.computeSha256Digest(accountName.getBytes())); 1895d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov serializer.attribute(null, ATTR_PACKAGE, packageName); 1905d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov serializer.attribute(null, ATTR_DIGEST, digest); 1915d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov serializer.endTag(null, TAG_PERMISSION); 1925d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1935d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1945d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } while (cursor.moveToNext()); 1955d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 1965d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov serializer.endTag(null, TAG_PERMISSIONS); 1975d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov serializer.endDocument(); 1985d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov serializer.flush(); 1995d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } catch (IOException e) { 2005d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov Log.e(TAG, "Error backing up account access grants", e); 2015d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov return null; 2025d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2035d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 2045d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov return dataStream.toByteArray(); 2055d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2065d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2075d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2085d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 2095d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov public void restoreAccountAccessPermissions(byte[] data, int userId) { 2105d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov try { 2115d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov ByteArrayInputStream dataStream = new ByteArrayInputStream(data); 2125d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov XmlPullParser parser = Xml.newPullParser(); 2135d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov parser.setInput(dataStream, StandardCharsets.UTF_8.name()); 2145d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov PackageManager packageManager = mAccountManagerService.mContext.getPackageManager(); 2155d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 2165d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final int permissionsOuterDepth = parser.getDepth(); 2175d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov while (XmlUtils.nextElementWithin(parser, permissionsOuterDepth)) { 2185d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (!TAG_PERMISSIONS.equals(parser.getName())) { 2195d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov continue; 2205d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2215d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final int permissionOuterDepth = parser.getDepth(); 2225d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov while (XmlUtils.nextElementWithin(parser, permissionOuterDepth)) { 2235d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (!TAG_PERMISSION.equals(parser.getName())) { 2245d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov continue; 2255d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2265d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov String accountDigest = parser.getAttributeValue(null, ATTR_ACCOUNT_SHA_256); 2275d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (TextUtils.isEmpty(accountDigest)) { 2285d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov XmlUtils.skipCurrentTag(parser); 2295d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2305d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov String packageName = parser.getAttributeValue(null, ATTR_PACKAGE); 2315d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (TextUtils.isEmpty(packageName)) { 2325d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov XmlUtils.skipCurrentTag(parser); 2335d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2345d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov String digest = parser.getAttributeValue(null, ATTR_DIGEST); 2355d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (TextUtils.isEmpty(digest)) { 2365d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov XmlUtils.skipCurrentTag(parser); 2375d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2385d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 2395d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov PendingAppPermission pendingAppPermission = new PendingAppPermission( 2405d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov accountDigest, packageName, digest, userId); 2415d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 2425d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (!pendingAppPermission.apply(packageManager)) { 2435d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov synchronized (mLock) { 2445d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov // Start watching before add pending to avoid a missed signal 2455d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (mRestorePackageMonitor == null) { 2465d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePackageMonitor = new RestorePackageMonitor(); 2475d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePackageMonitor.register(mAccountManagerService.mContext, 2485d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mAccountManagerService.mHandler.getLooper(), true); 2495d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2505d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (mRestorePendingAppPermissions == null) { 2515d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePendingAppPermissions = new ArrayList<>(); 2525d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2535d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePendingAppPermissions.add(pendingAppPermission); 2545d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2555d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2565d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2575d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2585d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 2595d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov // Make sure we eventually prune the in-memory pending restores 2605d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestoreCancelCommand = new CancelRestoreCommand(); 2615d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mAccountManagerService.mHandler.postDelayed(mRestoreCancelCommand, 2625d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov PENDING_RESTORE_TIMEOUT_MILLIS); 2635d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } catch (XmlPullParserException | IOException e) { 2645d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov Log.e(TAG, "Error restoring app permissions", e); 2655d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2665d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2675d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 2685d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final class RestorePackageMonitor extends PackageMonitor { 2695d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov @Override 2705d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov public void onPackageAdded(String packageName, int uid) { 2715d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov synchronized (mLock) { 2725d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (mRestorePendingAppPermissions == null) { 2735d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov return; 2745d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2755d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) { 2765d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov return; 2775d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2785d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final int count = mRestorePendingAppPermissions.size(); 2795d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov for (int i = count - 1; i >= 0; i--) { 2805d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov PendingAppPermission pendingAppPermission = 2815d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePendingAppPermissions.get(i); 2825d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (!pendingAppPermission.packageName.equals(packageName)) { 2835d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov continue; 2845d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2855d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (pendingAppPermission.apply( 2865d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mAccountManagerService.mContext.getPackageManager())) { 2875d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePendingAppPermissions.remove(i); 2885d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2895d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2905d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (mRestorePendingAppPermissions.isEmpty() 2915d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov && mRestoreCancelCommand != null) { 2925d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mAccountManagerService.mHandler.removeCallbacks(mRestoreCancelCommand); 2935d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestoreCancelCommand.run(); 2945d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestoreCancelCommand = null; 2955d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2965d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2975d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2985d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2995d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 3005d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final class CancelRestoreCommand implements Runnable { 3015d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov @Override 3025d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov public void run() { 3035d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov synchronized (mLock) { 3045d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePendingAppPermissions = null; 3055d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (mRestorePackageMonitor != null) { 3065d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePackageMonitor.unregister(); 3075d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePackageMonitor = null; 3085d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 3095d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 3105d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 3115d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 3125d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov} 313