10acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki/* 20acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki * Copyright (C) 2016 The Android Open Source Project 30acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki * 40acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki * Licensed under the Apache License, Version 2.0 (the "License"); 50acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki * you may not use this file except in compliance with the License. 60acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki * You may obtain a copy of the License at 70acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki * 80acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki * http://www.apache.org/licenses/LICENSE-2.0 90acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki * 100acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki * Unless required by applicable law or agreed to in writing, software 110acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki * distributed under the License is distributed on an "AS IS" BASIS, 120acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki * See the License for the specific language governing permissions and 140acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki * limitations under the License. 150acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki */ 160acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onukipackage com.android.server.pm; 170acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 1822fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onukiimport android.annotation.NonNull; 190acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onukiimport android.annotation.UserIdInt; 200acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onukiimport android.content.pm.PackageInfo; 210acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onukiimport android.util.Slog; 220acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 23c8c3329dd918b8ea16d6317d19ddee12325800f3Makoto Onukiimport com.android.internal.annotations.VisibleForTesting; 249da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onukiimport com.android.server.backup.BackupUtils; 250acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 260acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onukiimport libcore.util.HexEncoding; 270acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 280acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onukiimport org.xmlpull.v1.XmlPullParser; 290acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onukiimport org.xmlpull.v1.XmlPullParserException; 300acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onukiimport org.xmlpull.v1.XmlSerializer; 310acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 320acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onukiimport java.io.IOException; 330acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onukiimport java.io.PrintWriter; 340acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onukiimport java.util.ArrayList; 359f00d71787774bf79d4b398c28630f670765b791Tobias Thiererimport java.util.Base64; 360acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 370acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki/** 380acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki * Package information used by {@link android.content.pm.ShortcutManager} for backup / restore. 3922fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki * 4022fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki * All methods should be guarded by {@code ShortcutService.mLock}. 410acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki */ 429da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onukiclass ShortcutPackageInfo { 430acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki private static final String TAG = ShortcutService.TAG; 440acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 450acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki static final String TAG_ROOT = "package-info"; 460acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki private static final String ATTR_VERSION = "version"; 4722fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki private static final String ATTR_LAST_UPDATE_TIME = "last_udpate_time"; 480acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki private static final String ATTR_SHADOW = "shadow"; 490acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 500acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki private static final String TAG_SIGNATURE = "signature"; 510acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki private static final String ATTR_SIGNATURE_HASH = "hash"; 520acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 5339686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki private static final int VERSION_UNKNOWN = -1; 5439686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki 550acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki /** 560acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki * When true, this package information was restored from the previous device, and the app hasn't 570acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki * been installed yet. 580acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki */ 590acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki private boolean mIsShadow; 6039686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki private int mVersionCode = VERSION_UNKNOWN; 6122fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki private long mLastUpdateTime; 620acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki private ArrayList<byte[]> mSigHashes; 630acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 6422fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki private ShortcutPackageInfo(int versionCode, long lastUpdateTime, 6522fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki ArrayList<byte[]> sigHashes, boolean isShadow) { 660acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki mVersionCode = versionCode; 6722fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki mLastUpdateTime = lastUpdateTime; 680acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki mIsShadow = isShadow; 690acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki mSigHashes = sigHashes; 700acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 710acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 729da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki public static ShortcutPackageInfo newEmpty() { 7322fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki return new ShortcutPackageInfo(VERSION_UNKNOWN, /* last update time =*/ 0, 7422fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki new ArrayList<>(0), /* isShadow */ false); 75d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki } 76d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki 770acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki public boolean isShadow() { 780acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki return mIsShadow; 790acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 800acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 810acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki public void setShadow(boolean shadow) { 820acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki mIsShadow = shadow; 830acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 840acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 850acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki public int getVersionCode() { 860acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki return mVersionCode; 870acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 880acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 8922fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki public long getLastUpdateTime() { 9022fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki return mLastUpdateTime; 9122fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki } 9222fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki 93c8c3329dd918b8ea16d6317d19ddee12325800f3Makoto Onuki /** Set {@link #mVersionCode} and {@link #mLastUpdateTime} from a {@link PackageInfo}. */ 9422fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki public void updateVersionInfo(@NonNull PackageInfo pi) { 9522fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki if (pi != null) { 9622fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki mVersionCode = pi.versionCode; 9722fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki mLastUpdateTime = pi.lastUpdateTime; 9822fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki } 9939686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki } 10039686e8cdec3550c941d376929084f59ac0d78cdMakoto Onuki 1012e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki public boolean hasSignatures() { 1022e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki return mSigHashes.size() > 0; 1032e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki } 1042e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 1052e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki public boolean canRestoreTo(ShortcutService s, PackageInfo target) { 1062e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki if (!s.shouldBackupApp(target)) { 1072e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki // "allowBackup" was true when backed up, but now false. 1082e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki Slog.w(TAG, "Can't restore: package no longer allows backup"); 1092e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki return false; 1102e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki } 1110acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki if (target.versionCode < mVersionCode) { 1122e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki Slog.w(TAG, String.format( 1132e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki "Can't restore: package current version %d < backed up version %d", 1140acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki target.versionCode, mVersionCode)); 1150acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki return false; 1160acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 1179da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki if (!BackupUtils.signaturesMatch(mSigHashes, target)) { 1182e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki Slog.w(TAG, "Can't restore: Package signature mismatch"); 1190acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki return false; 1200acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 1210acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki return true; 1220acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 1230acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 124c8c3329dd918b8ea16d6317d19ddee12325800f3Makoto Onuki @VisibleForTesting 125c8c3329dd918b8ea16d6317d19ddee12325800f3Makoto Onuki public static ShortcutPackageInfo generateForInstalledPackageForTest( 1269da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki ShortcutService s, String packageName, @UserIdInt int packageUserId) { 1279da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki final PackageInfo pi = s.getPackageInfoWithSignatures(packageName, packageUserId); 1280acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki if (pi.signatures == null || pi.signatures.length == 0) { 1290acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki Slog.e(TAG, "Can't get signatures: package=" + packageName); 1300acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki return null; 1310acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 13222fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.versionCode, pi.lastUpdateTime, 1339da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki BackupUtils.hashSignatureArray(pi.signatures), /* shadow=*/ false); 1340acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 1350acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki return ret; 1360acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 1370acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 138c8c3329dd918b8ea16d6317d19ddee12325800f3Makoto Onuki public void refreshSignature(ShortcutService s, ShortcutPackageItem pkg) { 1392e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki if (mIsShadow) { 1402e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki s.wtf("Attempted to refresh package info for shadow package " + pkg.getPackageName() 1412e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki + ", user=" + pkg.getOwnerUserId()); 1422e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki return; 1432e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki } 1449da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki // Note use mUserId here, rather than userId. 1459da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki final PackageInfo pi = s.getPackageInfoWithSignatures( 1469da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki pkg.getPackageName(), pkg.getPackageUserId()); 1470acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki if (pi == null) { 1489da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki Slog.w(TAG, "Package not found: " + pkg.getPackageName()); 1490acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki return; 1500acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 1519da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki mSigHashes = BackupUtils.hashSignatureArray(pi.signatures); 1520acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 1530acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 1549da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki public void saveToXml(XmlSerializer out) throws IOException { 1550acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 1560acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki out.startTag(null, TAG_ROOT); 1570acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 1580acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki ShortcutService.writeAttr(out, ATTR_VERSION, mVersionCode); 15922fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki ShortcutService.writeAttr(out, ATTR_LAST_UPDATE_TIME, mLastUpdateTime); 1600acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki ShortcutService.writeAttr(out, ATTR_SHADOW, mIsShadow); 1610acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 1620acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki for (int i = 0; i < mSigHashes.size(); i++) { 1630acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki out.startTag(null, TAG_SIGNATURE); 1649f00d71787774bf79d4b398c28630f670765b791Tobias Thierer final String encoded = Base64.getEncoder().encodeToString(mSigHashes.get(i)); 1659f00d71787774bf79d4b398c28630f670765b791Tobias Thierer ShortcutService.writeAttr(out, ATTR_SIGNATURE_HASH, encoded); 1660acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki out.endTag(null, TAG_SIGNATURE); 1670acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 1680acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki out.endTag(null, TAG_ROOT); 1690acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 1700acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 1712e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki public void loadFromXml(XmlPullParser parser, boolean fromBackup) 1720acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki throws IOException, XmlPullParserException { 1730acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 1740acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION); 1750acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 176440a1ea8e2204ecb171e0187318beb2f08f6012cMakoto Onuki final long lastUpdateTime = ShortcutService.parseLongAttribute( 17722fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki parser, ATTR_LAST_UPDATE_TIME); 17822fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki 1792e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki // When restoring from backup, it's always shadow. 1802e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki final boolean shadow = 1812e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki fromBackup || ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW); 1820acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 1832e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki final ArrayList<byte[]> hashes = new ArrayList<>(); 1840acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 1850acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki final int outerDepth = parser.getDepth(); 1860acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki int type; 1870acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1880acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 1890acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki if (type != XmlPullParser.START_TAG) { 1900acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki continue; 1910acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 1920acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki final int depth = parser.getDepth(); 1930acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki final String tag = parser.getName(); 1949da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki 1959da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki if (depth == outerDepth + 1) { 1969da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki switch (tag) { 1979da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki case TAG_SIGNATURE: { 1989da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki final String hash = ShortcutService.parseStringAttribute( 1999da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki parser, ATTR_SIGNATURE_HASH); 2009f00d71787774bf79d4b398c28630f670765b791Tobias Thierer // Throws IllegalArgumentException if hash is invalid base64 data 2019f00d71787774bf79d4b398c28630f670765b791Tobias Thierer final byte[] decoded = Base64.getDecoder().decode(hash); 2029f00d71787774bf79d4b398c28630f670765b791Tobias Thierer hashes.add(decoded); 2039da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki continue; 2049da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki } 2050acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 2060acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 2079da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki ShortcutService.warnForInvalidTag(depth, tag); 2080acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 2092e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki 2102e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki // Successfully loaded; replace the feilds. 2112e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki mVersionCode = versionCode; 21222fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki mLastUpdateTime = lastUpdateTime; 2132e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki mIsShadow = shadow; 2142e210c4d0f766e52ea4c087a1d54213c36a4e0eaMakoto Onuki mSigHashes = hashes; 2150acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 2160acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 217c51b2876ec5c0af449469a0f76bb38c51cfcff04Makoto Onuki public void dump(PrintWriter pw, String prefix) { 2180acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki pw.println(); 2190acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 2200acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki pw.print(prefix); 2219da23fc6ac565b38129d52f4f8f174c833a9bd01Makoto Onuki pw.println("PackageInfo:"); 222d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki 223d99c6f04bbb68f8be78f2c3ca625a3a8d5645275Makoto Onuki pw.print(prefix); 2240acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki pw.print(" IsShadow: "); 2250acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki pw.print(mIsShadow); 2260acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki pw.println(); 2270acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 2280acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki pw.print(prefix); 2290acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki pw.print(" Version: "); 2300acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki pw.print(mVersionCode); 2310acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki pw.println(); 2320acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki 23322fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki pw.print(prefix); 23422fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki pw.print(" Last package update time: "); 23522fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki pw.print(mLastUpdateTime); 23622fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki pw.println(); 23722fcc68e6be0edaa98f3dacf79d580a5e5d50005Makoto Onuki 2380acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki for (int i = 0; i < mSigHashes.size(); i++) { 2390acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki pw.print(prefix); 2400acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki pw.print(" "); 2410acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki pw.print("SigHash: "); 2420acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki pw.println(HexEncoding.encode(mSigHashes.get(i))); 2430acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 2440acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki } 2450acbb14574d859b5f1cc0b7c6bbdfbeba38f3e55Makoto Onuki} 246