Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 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 | */ |
| 16 | package com.android.server.pm; |
| 17 | |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 18 | import android.annotation.UserIdInt; |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 19 | import android.content.pm.PackageInfo; |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 20 | import android.util.Slog; |
| 21 | |
Makoto Onuki | 9da23fc | 2016-03-29 11:14:42 -0700 | [diff] [blame] | 22 | import com.android.server.backup.BackupUtils; |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 23 | |
| 24 | import libcore.io.Base64; |
| 25 | import libcore.util.HexEncoding; |
| 26 | |
| 27 | import org.xmlpull.v1.XmlPullParser; |
| 28 | import org.xmlpull.v1.XmlPullParserException; |
| 29 | import org.xmlpull.v1.XmlSerializer; |
| 30 | |
| 31 | import java.io.IOException; |
| 32 | import java.io.PrintWriter; |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 33 | import java.util.ArrayList; |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 34 | |
| 35 | /** |
| 36 | * Package information used by {@link android.content.pm.ShortcutManager} for backup / restore. |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 37 | */ |
Makoto Onuki | 9da23fc | 2016-03-29 11:14:42 -0700 | [diff] [blame] | 38 | class ShortcutPackageInfo { |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 39 | private static final String TAG = ShortcutService.TAG; |
| 40 | |
| 41 | static final String TAG_ROOT = "package-info"; |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 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 | |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 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 | |
Makoto Onuki | 9da23fc | 2016-03-29 11:14:42 -0700 | [diff] [blame] | 56 | private ShortcutPackageInfo(int versionCode, ArrayList<byte[]> sigHashes, boolean isShadow) { |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 57 | mVersionCode = versionCode; |
| 58 | mIsShadow = isShadow; |
| 59 | mSigHashes = sigHashes; |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 60 | } |
| 61 | |
Makoto Onuki | 9da23fc | 2016-03-29 11:14:42 -0700 | [diff] [blame] | 62 | public static ShortcutPackageInfo newEmpty() { |
| 63 | return new ShortcutPackageInfo(0, new ArrayList<>(0), /* isShadow */ false); |
Makoto Onuki | d99c6f0 | 2016-03-28 11:02:54 -0700 | [diff] [blame] | 64 | } |
| 65 | |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 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 | |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 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 | } |
Makoto Onuki | 9da23fc | 2016-03-29 11:14:42 -0700 | [diff] [blame] | 88 | if (!BackupUtils.signaturesMatch(mSigHashes, target)) { |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 89 | Slog.w(TAG, "Package signature mismtach"); |
| 90 | return false; |
| 91 | } |
| 92 | return true; |
| 93 | } |
| 94 | |
| 95 | public static ShortcutPackageInfo generateForInstalledPackage( |
Makoto Onuki | 9da23fc | 2016-03-29 11:14:42 -0700 | [diff] [blame] | 96 | ShortcutService s, String packageName, @UserIdInt int packageUserId) { |
| 97 | final PackageInfo pi = s.getPackageInfoWithSignatures(packageName, packageUserId); |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 98 | if (pi.signatures == null || pi.signatures.length == 0) { |
| 99 | Slog.e(TAG, "Can't get signatures: package=" + packageName); |
| 100 | return null; |
| 101 | } |
Makoto Onuki | 9da23fc | 2016-03-29 11:14:42 -0700 | [diff] [blame] | 102 | final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.versionCode, |
| 103 | BackupUtils.hashSignatureArray(pi.signatures), /* shadow=*/ false); |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 104 | |
| 105 | return ret; |
| 106 | } |
| 107 | |
Makoto Onuki | 9da23fc | 2016-03-29 11:14:42 -0700 | [diff] [blame] | 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()); |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 112 | if (pi == null) { |
Makoto Onuki | 9da23fc | 2016-03-29 11:14:42 -0700 | [diff] [blame] | 113 | Slog.w(TAG, "Package not found: " + pkg.getPackageName()); |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 114 | return; |
| 115 | } |
| 116 | mVersionCode = pi.versionCode; |
Makoto Onuki | 9da23fc | 2016-03-29 11:14:42 -0700 | [diff] [blame] | 117 | mSigHashes = BackupUtils.hashSignatureArray(pi.signatures); |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 118 | } |
| 119 | |
Makoto Onuki | 9da23fc | 2016-03-29 11:14:42 -0700 | [diff] [blame] | 120 | public void saveToXml(XmlSerializer out) throws IOException { |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 121 | |
| 122 | out.startTag(null, TAG_ROOT); |
| 123 | |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 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 | |
Makoto Onuki | 9da23fc | 2016-03-29 11:14:42 -0700 | [diff] [blame] | 135 | public static ShortcutPackageInfo loadFromXml(XmlPullParser parser) |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 136 | throws IOException, XmlPullParserException { |
| 137 | |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 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(); |
Makoto Onuki | 9da23fc | 2016-03-29 11:14:42 -0700 | [diff] [blame] | 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 | } |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 162 | } |
| 163 | } |
Makoto Onuki | 9da23fc | 2016-03-29 11:14:42 -0700 | [diff] [blame] | 164 | ShortcutService.warnForInvalidTag(depth, tag); |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 165 | } |
Makoto Onuki | 9da23fc | 2016-03-29 11:14:42 -0700 | [diff] [blame] | 166 | return new ShortcutPackageInfo(versionCode, hashes, shadow); |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 167 | } |
| 168 | |
| 169 | public void dump(ShortcutService s, PrintWriter pw, String prefix) { |
| 170 | pw.println(); |
| 171 | |
| 172 | pw.print(prefix); |
Makoto Onuki | 9da23fc | 2016-03-29 11:14:42 -0700 | [diff] [blame] | 173 | pw.println("PackageInfo:"); |
Makoto Onuki | d99c6f0 | 2016-03-28 11:02:54 -0700 | [diff] [blame] | 174 | |
| 175 | pw.print(prefix); |
Makoto Onuki | 0acbb14 | 2016-03-22 17:02:57 -0700 | [diff] [blame] | 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 | } |