ShortcutPackageInfo.java revision 9da23fc6ac565b38129d52f4f8f174c833a9bd01
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package com.android.server.pm; 17 18import android.annotation.UserIdInt; 19import android.content.pm.PackageInfo; 20import android.util.Slog; 21 22import com.android.server.backup.BackupUtils; 23 24import libcore.io.Base64; 25import libcore.util.HexEncoding; 26 27import org.xmlpull.v1.XmlPullParser; 28import org.xmlpull.v1.XmlPullParserException; 29import org.xmlpull.v1.XmlSerializer; 30 31import java.io.IOException; 32import java.io.PrintWriter; 33import java.util.ArrayList; 34 35/** 36 * Package information used by {@link android.content.pm.ShortcutManager} for backup / restore. 37 */ 38class ShortcutPackageInfo { 39 private static final String TAG = ShortcutService.TAG; 40 41 static final String TAG_ROOT = "package-info"; 42 private static final String ATTR_VERSION = "version"; 43 private static final String ATTR_SHADOW = "shadow"; 44 45 private static final String TAG_SIGNATURE = "signature"; 46 private static final String ATTR_SIGNATURE_HASH = "hash"; 47 48 /** 49 * When true, this package information was restored from the previous device, and the app hasn't 50 * been installed yet. 51 */ 52 private boolean mIsShadow; 53 private int mVersionCode; 54 private ArrayList<byte[]> mSigHashes; 55 56 private ShortcutPackageInfo(int versionCode, ArrayList<byte[]> sigHashes, boolean isShadow) { 57 mVersionCode = versionCode; 58 mIsShadow = isShadow; 59 mSigHashes = sigHashes; 60 } 61 62 public static ShortcutPackageInfo newEmpty() { 63 return new ShortcutPackageInfo(0, new ArrayList<>(0), /* isShadow */ false); 64 } 65 66 public boolean isShadow() { 67 return mIsShadow; 68 } 69 70 public boolean isInstalled() { 71 return !mIsShadow; 72 } 73 74 public void setShadow(boolean shadow) { 75 mIsShadow = shadow; 76 } 77 78 public int getVersionCode() { 79 return mVersionCode; 80 } 81 82 public boolean canRestoreTo(PackageInfo target) { 83 if (target.versionCode < mVersionCode) { 84 Slog.w(TAG, String.format("Package current version %d < backed up version %d", 85 target.versionCode, mVersionCode)); 86 return false; 87 } 88 if (!BackupUtils.signaturesMatch(mSigHashes, target)) { 89 Slog.w(TAG, "Package signature mismtach"); 90 return false; 91 } 92 return true; 93 } 94 95 public static ShortcutPackageInfo generateForInstalledPackage( 96 ShortcutService s, String packageName, @UserIdInt int packageUserId) { 97 final PackageInfo pi = s.getPackageInfoWithSignatures(packageName, packageUserId); 98 if (pi.signatures == null || pi.signatures.length == 0) { 99 Slog.e(TAG, "Can't get signatures: package=" + packageName); 100 return null; 101 } 102 final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.versionCode, 103 BackupUtils.hashSignatureArray(pi.signatures), /* shadow=*/ false); 104 105 return ret; 106 } 107 108 public void refresh(ShortcutService s, ShortcutPackageItem pkg) { 109 // Note use mUserId here, rather than userId. 110 final PackageInfo pi = s.getPackageInfoWithSignatures( 111 pkg.getPackageName(), pkg.getPackageUserId()); 112 if (pi == null) { 113 Slog.w(TAG, "Package not found: " + pkg.getPackageName()); 114 return; 115 } 116 mVersionCode = pi.versionCode; 117 mSigHashes = BackupUtils.hashSignatureArray(pi.signatures); 118 } 119 120 public void saveToXml(XmlSerializer out) throws IOException { 121 122 out.startTag(null, TAG_ROOT); 123 124 ShortcutService.writeAttr(out, ATTR_VERSION, mVersionCode); 125 ShortcutService.writeAttr(out, ATTR_SHADOW, mIsShadow); 126 127 for (int i = 0; i < mSigHashes.size(); i++) { 128 out.startTag(null, TAG_SIGNATURE); 129 ShortcutService.writeAttr(out, ATTR_SIGNATURE_HASH, Base64.encode(mSigHashes.get(i))); 130 out.endTag(null, TAG_SIGNATURE); 131 } 132 out.endTag(null, TAG_ROOT); 133 } 134 135 public static ShortcutPackageInfo loadFromXml(XmlPullParser parser) 136 throws IOException, XmlPullParserException { 137 138 final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION); 139 final boolean shadow = ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW); 140 141 final ArrayList<byte[]> hashes = new ArrayList<>(); 142 143 144 final int outerDepth = parser.getDepth(); 145 int type; 146 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 147 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 148 if (type != XmlPullParser.START_TAG) { 149 continue; 150 } 151 final int depth = parser.getDepth(); 152 final String tag = parser.getName(); 153 154 if (depth == outerDepth + 1) { 155 switch (tag) { 156 case TAG_SIGNATURE: { 157 final String hash = ShortcutService.parseStringAttribute( 158 parser, ATTR_SIGNATURE_HASH); 159 hashes.add(Base64.decode(hash.getBytes())); 160 continue; 161 } 162 } 163 } 164 ShortcutService.warnForInvalidTag(depth, tag); 165 } 166 return new ShortcutPackageInfo(versionCode, hashes, shadow); 167 } 168 169 public void dump(ShortcutService s, PrintWriter pw, String prefix) { 170 pw.println(); 171 172 pw.print(prefix); 173 pw.println("PackageInfo:"); 174 175 pw.print(prefix); 176 pw.print(" IsShadow: "); 177 pw.print(mIsShadow); 178 pw.println(); 179 180 pw.print(prefix); 181 pw.print(" Version: "); 182 pw.print(mVersionCode); 183 pw.println(); 184 185 for (int i = 0; i < mSigHashes.size(); i++) { 186 pw.print(prefix); 187 pw.print(" "); 188 pw.print("SigHash: "); 189 pw.println(HexEncoding.encode(mSigHashes.get(i))); 190 } 191 } 192} 193