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; 26cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganovimport android.content.pm.Signature; 275d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.database.Cursor; 285d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.database.sqlite.SQLiteDatabase; 295d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.os.UserHandle; 305d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.text.TextUtils; 315d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.util.Log; 325d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.util.PackageUtils; 331ce0161e30de2585f67e9c42ad98b33ab0333f46Fyodor Kupolovimport android.util.Pair; 34cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganovimport android.util.Slog; 355d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport android.util.Xml; 365d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport com.android.internal.annotations.GuardedBy; 375d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport com.android.internal.content.PackageMonitor; 385d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport com.android.internal.util.FastXmlSerializer; 395d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport com.android.internal.util.XmlUtils; 401ce0161e30de2585f67e9c42ad98b33ab0333f46Fyodor Kupolovimport com.android.server.accounts.AccountsDb.DeDatabaseHelper; 411ce0161e30de2585f67e9c42ad98b33ab0333f46Fyodor Kupolov 425d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport org.xmlpull.v1.XmlPullParser; 435d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport org.xmlpull.v1.XmlPullParserException; 445d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport org.xmlpull.v1.XmlSerializer; 455d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 465d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport java.io.ByteArrayInputStream; 475d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport java.io.ByteArrayOutputStream; 485d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport java.io.IOException; 495d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport java.nio.charset.StandardCharsets; 505d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport java.util.ArrayList; 515d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovimport java.util.List; 525d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 535d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov/** 545d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov * Helper class for backup and restore of account access grants. 555d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov */ 565d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganovpublic final class AccountManagerBackupHelper { 575d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private static final String TAG = "AccountManagerBackupHelper"; 585d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 595d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private static final long PENDING_RESTORE_TIMEOUT_MILLIS = 60 * 60 * 1000; // 1 hour 605d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 615d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private static final String TAG_PERMISSIONS = "permissions"; 625d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private static final String TAG_PERMISSION = "permission"; 635d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private static final String ATTR_ACCOUNT_SHA_256 = "account-sha-256"; 645d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private static final String ATTR_PACKAGE = "package"; 655d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private static final String ATTR_DIGEST = "digest"; 665d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 675d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final Object mLock = new Object(); 685d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 695d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final AccountManagerService mAccountManagerService; 705d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final AccountManagerInternal mAccountManagerInternal; 715d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 725d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov @GuardedBy("mLock") 735d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private List<PendingAppPermission> mRestorePendingAppPermissions; 745d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 755d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov @GuardedBy("mLock") 765d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private RestorePackageMonitor mRestorePackageMonitor; 775d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 785d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov @GuardedBy("mLock") 795d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private Runnable mRestoreCancelCommand; 805d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 815d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov public AccountManagerBackupHelper(AccountManagerService accountManagerService, 825d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov AccountManagerInternal accountManagerInternal) { 835d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mAccountManagerService = accountManagerService; 845d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mAccountManagerInternal = accountManagerInternal; 855d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 865d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 875d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final class PendingAppPermission { 885d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final @NonNull String accountDigest; 895d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final @NonNull String packageName; 905d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final @NonNull String certDigest; 915d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final @IntRange(from = 0) int userId; 925d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 935d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov public PendingAppPermission(String accountDigest, String packageName, 945d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov String certDigest, int userId) { 955d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov this.accountDigest = accountDigest; 965d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov this.packageName = packageName; 975d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov this.certDigest = certDigest; 985d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov this.userId = userId; 995d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1005d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 1015d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov public boolean apply(PackageManager packageManager) { 1025d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov Account account = null; 1035d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov AccountManagerService.UserAccounts accounts = mAccountManagerService 1045d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov .getUserAccounts(userId); 1058cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov synchronized (accounts.dbLock) { 1068cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov synchronized (accounts.cacheLock) { 1078cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov for (Account[] accountsPerType : accounts.accountCache.values()) { 1088cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov for (Account accountPerType : accountsPerType) { 1098cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov if (accountDigest.equals(PackageUtils.computeSha256Digest( 1108cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov accountPerType.name.getBytes()))) { 1118cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov account = accountPerType; 1128cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov break; 1138cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov } 1148cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov } 1158cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov if (account != null) { 1165d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov break; 1175d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1185d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1195d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1205d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1215d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (account == null) { 1225d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov return false; 1235d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1245d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final PackageInfo packageInfo; 1255d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov try { 1265d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov packageInfo = packageManager.getPackageInfoAsUser(packageName, 1275d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov PackageManager.GET_SIGNATURES, userId); 1285d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } catch (PackageManager.NameNotFoundException e) { 1295d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov return false; 1305d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 131cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov 132cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov // Before we used only the first signature to compute the SHA 256 but some 133cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov // apps could be singed by multiple certs and the cert order is undefined. 134cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov // We prefer the modern computation procedure where all certs are taken 135cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov // into account but also allow the value from the old computation to allow 136cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov // restoring backed up grants on an older platform version. 137cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov final String[] signaturesSha256Digests = PackageUtils.computeSignaturesSha256Digests( 138cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov packageInfo.signatures); 139cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov final String signaturesSha256Digest = PackageUtils.computeSignaturesSha256Digest( 140cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov signaturesSha256Digests); 141cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov if (!certDigest.equals(signaturesSha256Digest) && (packageInfo.signatures.length <= 1 142cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov || !certDigest.equals(signaturesSha256Digests[0]))) { 1435d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov return false; 1445d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1455d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final int uid = packageInfo.applicationInfo.uid; 1465d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (!mAccountManagerInternal.hasAccountAccess(account, uid)) { 1475d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mAccountManagerService.grantAppPermission(account, 1485d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov AccountManager.ACCOUNT_ACCESS_TOKEN_TYPE, uid); 1495d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1505d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov return true; 1515d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1525d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 1535d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 1545d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov public byte[] backupAccountAccessPermissions(int userId) { 1555d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final AccountManagerService.UserAccounts accounts = mAccountManagerService 1565d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov .getUserAccounts(userId); 1578cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov synchronized (accounts.dbLock) { 1588cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov synchronized (accounts.cacheLock) { 1598cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov List<Pair<String, Integer>> allAccountGrants = accounts.accountsDb 1608cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov .findAllAccountGrants(); 1618cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov if (allAccountGrants.isEmpty()) { 1628cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov return null; 1638cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov } 1648cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov try { 1658cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); 1668cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov final XmlSerializer serializer = new FastXmlSerializer(); 1678cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov serializer.setOutput(dataStream, StandardCharsets.UTF_8.name()); 1688cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov serializer.startDocument(null, true); 1698cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov serializer.startTag(null, TAG_PERMISSIONS); 1708cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov 1718cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov PackageManager packageManager = mAccountManagerService.mContext 1728cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov .getPackageManager(); 1738cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov for (Pair<String, Integer> grant : allAccountGrants) { 1748cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov final String accountName = grant.first; 1758cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov final int uid = grant.second; 1768cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov 1778cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov final String[] packageNames = packageManager.getPackagesForUid(uid); 1788cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov if (packageNames == null) { 1798cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov continue; 1808cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov } 1815d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 1828cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov for (String packageName : packageNames) { 183cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov final PackageInfo packageInfo; 184cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov try { 185cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov packageInfo = packageManager.getPackageInfoAsUser(packageName, 186cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov PackageManager.GET_SIGNATURES, userId); 187cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov } catch (PackageManager.NameNotFoundException e) { 188cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov Slog.i(TAG, "Skipping backup of account access grant for" 189cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov + " non-existing package: " + packageName); 190cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov continue; 191cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov } 192cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov final String digest = PackageUtils.computeSignaturesSha256Digest( 193cdd685c07504223e37e7831ce592446ec4ac6f6aSvetoslav Ganov packageInfo.signatures); 1948cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov if (digest != null) { 1958cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov serializer.startTag(null, TAG_PERMISSION); 1968cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov serializer.attribute(null, ATTR_ACCOUNT_SHA_256, 1978cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov PackageUtils.computeSha256Digest(accountName.getBytes())); 1988cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov serializer.attribute(null, ATTR_PACKAGE, packageName); 1998cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov serializer.attribute(null, ATTR_DIGEST, digest); 2008cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov serializer.endTag(null, TAG_PERMISSION); 2018cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov } 2025d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2031ce0161e30de2585f67e9c42ad98b33ab0333f46Fyodor Kupolov } 2048cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov serializer.endTag(null, TAG_PERMISSIONS); 2058cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov serializer.endDocument(); 2068cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov serializer.flush(); 2078cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov return dataStream.toByteArray(); 2088cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov } catch (IOException e) { 2098cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov Log.e(TAG, "Error backing up account access grants", e); 2108cd927d8ea08cba89ac02dfd50ed42b486bd7f53Fyodor Kupolov return null; 2115d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2125d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2135d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2145d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2155d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 2165d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov public void restoreAccountAccessPermissions(byte[] data, int userId) { 2175d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov try { 2185d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov ByteArrayInputStream dataStream = new ByteArrayInputStream(data); 2195d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov XmlPullParser parser = Xml.newPullParser(); 2205d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov parser.setInput(dataStream, StandardCharsets.UTF_8.name()); 2215d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov PackageManager packageManager = mAccountManagerService.mContext.getPackageManager(); 2225d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 2235d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final int permissionsOuterDepth = parser.getDepth(); 2245d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov while (XmlUtils.nextElementWithin(parser, permissionsOuterDepth)) { 2255d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (!TAG_PERMISSIONS.equals(parser.getName())) { 2265d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov continue; 2275d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2285d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final int permissionOuterDepth = parser.getDepth(); 2295d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov while (XmlUtils.nextElementWithin(parser, permissionOuterDepth)) { 2305d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (!TAG_PERMISSION.equals(parser.getName())) { 2315d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov continue; 2325d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2335d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov String accountDigest = parser.getAttributeValue(null, ATTR_ACCOUNT_SHA_256); 2345d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (TextUtils.isEmpty(accountDigest)) { 2355d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov XmlUtils.skipCurrentTag(parser); 2365d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2375d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov String packageName = parser.getAttributeValue(null, ATTR_PACKAGE); 2385d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (TextUtils.isEmpty(packageName)) { 2395d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov XmlUtils.skipCurrentTag(parser); 2405d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2415d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov String digest = parser.getAttributeValue(null, ATTR_DIGEST); 2425d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (TextUtils.isEmpty(digest)) { 2435d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov XmlUtils.skipCurrentTag(parser); 2445d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2455d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 2465d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov PendingAppPermission pendingAppPermission = new PendingAppPermission( 2475d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov accountDigest, packageName, digest, userId); 2485d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 2495d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (!pendingAppPermission.apply(packageManager)) { 2505d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov synchronized (mLock) { 2515d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov // Start watching before add pending to avoid a missed signal 2525d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (mRestorePackageMonitor == null) { 2535d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePackageMonitor = new RestorePackageMonitor(); 2545d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePackageMonitor.register(mAccountManagerService.mContext, 2555d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mAccountManagerService.mHandler.getLooper(), true); 2565d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2575d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (mRestorePendingAppPermissions == null) { 2585d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePendingAppPermissions = new ArrayList<>(); 2595d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2605d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePendingAppPermissions.add(pendingAppPermission); 2615d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2625d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2635d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2645d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2655d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 2665d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov // Make sure we eventually prune the in-memory pending restores 2675d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestoreCancelCommand = new CancelRestoreCommand(); 2685d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mAccountManagerService.mHandler.postDelayed(mRestoreCancelCommand, 2695d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov PENDING_RESTORE_TIMEOUT_MILLIS); 2705d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } catch (XmlPullParserException | IOException e) { 2715d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov Log.e(TAG, "Error restoring app permissions", e); 2725d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2735d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2745d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 2755d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final class RestorePackageMonitor extends PackageMonitor { 2765d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov @Override 2775d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov public void onPackageAdded(String packageName, int uid) { 2785d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov synchronized (mLock) { 2795d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (mRestorePendingAppPermissions == null) { 2805d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov return; 2815d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2825d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) { 2835d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov return; 2845d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2855d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov final int count = mRestorePendingAppPermissions.size(); 2865d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov for (int i = count - 1; i >= 0; i--) { 2875d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov PendingAppPermission pendingAppPermission = 2885d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePendingAppPermissions.get(i); 2895d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (!pendingAppPermission.packageName.equals(packageName)) { 2905d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov continue; 2915d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2925d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (pendingAppPermission.apply( 2935d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mAccountManagerService.mContext.getPackageManager())) { 2945d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePendingAppPermissions.remove(i); 2955d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2965d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 2975d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (mRestorePendingAppPermissions.isEmpty() 2985d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov && mRestoreCancelCommand != null) { 2995d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mAccountManagerService.mHandler.removeCallbacks(mRestoreCancelCommand); 3005d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestoreCancelCommand.run(); 3015d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestoreCancelCommand = null; 3025d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 3035d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 3045d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 3055d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 3065d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov 3075d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov private final class CancelRestoreCommand implements Runnable { 3085d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov @Override 3095d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov public void run() { 3105d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov synchronized (mLock) { 3115d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePendingAppPermissions = null; 3125d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov if (mRestorePackageMonitor != null) { 3135d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePackageMonitor.unregister(); 3145d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov mRestorePackageMonitor = null; 3155d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 3165d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 3175d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 3185d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov } 3195d09c998a03eea53218c3b3c40e20db1b7693c9cSvet Ganov} 320