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