blob: 4de15de9ff71c3c8faa597bed2d7b5b4b494b5b6 [file] [log] [blame]
Makoto Onuki0acbb142016-03-22 17:02:57 -07001/*
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
Makoto Onuki22fcc682016-05-17 14:52:19 -070018import android.annotation.NonNull;
Makoto Onuki0acbb142016-03-22 17:02:57 -070019import android.annotation.UserIdInt;
Makoto Onuki0acbb142016-03-22 17:02:57 -070020import android.content.pm.PackageInfo;
Makoto Onuki0acbb142016-03-22 17:02:57 -070021import android.util.Slog;
22
Makoto Onukic8c33292016-09-12 16:36:59 -070023import com.android.internal.annotations.VisibleForTesting;
Makoto Onuki9da23fc2016-03-29 11:14:42 -070024import com.android.server.backup.BackupUtils;
Makoto Onuki0acbb142016-03-22 17:02:57 -070025
26import libcore.io.Base64;
27import libcore.util.HexEncoding;
28
29import org.xmlpull.v1.XmlPullParser;
30import org.xmlpull.v1.XmlPullParserException;
31import org.xmlpull.v1.XmlSerializer;
32
33import java.io.IOException;
34import java.io.PrintWriter;
Makoto Onuki0acbb142016-03-22 17:02:57 -070035import java.util.ArrayList;
Makoto Onuki0acbb142016-03-22 17:02:57 -070036
37/**
38 * Package information used by {@link android.content.pm.ShortcutManager} for backup / restore.
Makoto Onuki22fcc682016-05-17 14:52:19 -070039 *
40 * All methods should be guarded by {@code ShortcutService.mLock}.
Makoto Onuki0acbb142016-03-22 17:02:57 -070041 */
Makoto Onuki9da23fc2016-03-29 11:14:42 -070042class ShortcutPackageInfo {
Makoto Onuki0acbb142016-03-22 17:02:57 -070043 private static final String TAG = ShortcutService.TAG;
44
45 static final String TAG_ROOT = "package-info";
Makoto Onuki0acbb142016-03-22 17:02:57 -070046 private static final String ATTR_VERSION = "version";
Makoto Onuki22fcc682016-05-17 14:52:19 -070047 private static final String ATTR_LAST_UPDATE_TIME = "last_udpate_time";
Makoto Onuki0acbb142016-03-22 17:02:57 -070048 private static final String ATTR_SHADOW = "shadow";
49
50 private static final String TAG_SIGNATURE = "signature";
51 private static final String ATTR_SIGNATURE_HASH = "hash";
52
Makoto Onuki39686e82016-04-13 18:03:00 -070053 private static final int VERSION_UNKNOWN = -1;
54
Makoto Onuki0acbb142016-03-22 17:02:57 -070055 /**
56 * When true, this package information was restored from the previous device, and the app hasn't
57 * been installed yet.
58 */
59 private boolean mIsShadow;
Makoto Onuki39686e82016-04-13 18:03:00 -070060 private int mVersionCode = VERSION_UNKNOWN;
Makoto Onuki22fcc682016-05-17 14:52:19 -070061 private long mLastUpdateTime;
Makoto Onuki0acbb142016-03-22 17:02:57 -070062 private ArrayList<byte[]> mSigHashes;
63
Makoto Onuki22fcc682016-05-17 14:52:19 -070064 private ShortcutPackageInfo(int versionCode, long lastUpdateTime,
65 ArrayList<byte[]> sigHashes, boolean isShadow) {
Makoto Onuki0acbb142016-03-22 17:02:57 -070066 mVersionCode = versionCode;
Makoto Onuki22fcc682016-05-17 14:52:19 -070067 mLastUpdateTime = lastUpdateTime;
Makoto Onuki0acbb142016-03-22 17:02:57 -070068 mIsShadow = isShadow;
69 mSigHashes = sigHashes;
Makoto Onuki0acbb142016-03-22 17:02:57 -070070 }
71
Makoto Onuki9da23fc2016-03-29 11:14:42 -070072 public static ShortcutPackageInfo newEmpty() {
Makoto Onuki22fcc682016-05-17 14:52:19 -070073 return new ShortcutPackageInfo(VERSION_UNKNOWN, /* last update time =*/ 0,
74 new ArrayList<>(0), /* isShadow */ false);
Makoto Onukid99c6f02016-03-28 11:02:54 -070075 }
76
Makoto Onuki0acbb142016-03-22 17:02:57 -070077 public boolean isShadow() {
78 return mIsShadow;
79 }
80
Makoto Onuki0acbb142016-03-22 17:02:57 -070081 public void setShadow(boolean shadow) {
82 mIsShadow = shadow;
83 }
84
85 public int getVersionCode() {
86 return mVersionCode;
87 }
88
Makoto Onuki22fcc682016-05-17 14:52:19 -070089 public long getLastUpdateTime() {
90 return mLastUpdateTime;
91 }
92
Makoto Onukic8c33292016-09-12 16:36:59 -070093 /** Set {@link #mVersionCode} and {@link #mLastUpdateTime} from a {@link PackageInfo}. */
Makoto Onuki22fcc682016-05-17 14:52:19 -070094 public void updateVersionInfo(@NonNull PackageInfo pi) {
95 if (pi != null) {
96 mVersionCode = pi.versionCode;
97 mLastUpdateTime = pi.lastUpdateTime;
98 }
Makoto Onuki39686e82016-04-13 18:03:00 -070099 }
100
Makoto Onuki2e210c42016-03-30 08:30:36 -0700101 public boolean hasSignatures() {
102 return mSigHashes.size() > 0;
103 }
104
105 public boolean canRestoreTo(ShortcutService s, PackageInfo target) {
106 if (!s.shouldBackupApp(target)) {
107 // "allowBackup" was true when backed up, but now false.
108 Slog.w(TAG, "Can't restore: package no longer allows backup");
109 return false;
110 }
Makoto Onuki0acbb142016-03-22 17:02:57 -0700111 if (target.versionCode < mVersionCode) {
Makoto Onuki2e210c42016-03-30 08:30:36 -0700112 Slog.w(TAG, String.format(
113 "Can't restore: package current version %d < backed up version %d",
Makoto Onuki0acbb142016-03-22 17:02:57 -0700114 target.versionCode, mVersionCode));
115 return false;
116 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700117 if (!BackupUtils.signaturesMatch(mSigHashes, target)) {
Makoto Onuki2e210c42016-03-30 08:30:36 -0700118 Slog.w(TAG, "Can't restore: Package signature mismatch");
Makoto Onuki0acbb142016-03-22 17:02:57 -0700119 return false;
120 }
121 return true;
122 }
123
Makoto Onukic8c33292016-09-12 16:36:59 -0700124 @VisibleForTesting
125 public static ShortcutPackageInfo generateForInstalledPackageForTest(
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700126 ShortcutService s, String packageName, @UserIdInt int packageUserId) {
127 final PackageInfo pi = s.getPackageInfoWithSignatures(packageName, packageUserId);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700128 if (pi.signatures == null || pi.signatures.length == 0) {
129 Slog.e(TAG, "Can't get signatures: package=" + packageName);
130 return null;
131 }
Makoto Onuki22fcc682016-05-17 14:52:19 -0700132 final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.versionCode, pi.lastUpdateTime,
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700133 BackupUtils.hashSignatureArray(pi.signatures), /* shadow=*/ false);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700134
135 return ret;
136 }
137
Makoto Onukic8c33292016-09-12 16:36:59 -0700138 public void refreshSignature(ShortcutService s, ShortcutPackageItem pkg) {
Makoto Onuki2e210c42016-03-30 08:30:36 -0700139 if (mIsShadow) {
140 s.wtf("Attempted to refresh package info for shadow package " + pkg.getPackageName()
141 + ", user=" + pkg.getOwnerUserId());
142 return;
143 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700144 // Note use mUserId here, rather than userId.
145 final PackageInfo pi = s.getPackageInfoWithSignatures(
146 pkg.getPackageName(), pkg.getPackageUserId());
Makoto Onuki0acbb142016-03-22 17:02:57 -0700147 if (pi == null) {
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700148 Slog.w(TAG, "Package not found: " + pkg.getPackageName());
Makoto Onuki0acbb142016-03-22 17:02:57 -0700149 return;
150 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700151 mSigHashes = BackupUtils.hashSignatureArray(pi.signatures);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700152 }
153
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700154 public void saveToXml(XmlSerializer out) throws IOException {
Makoto Onuki0acbb142016-03-22 17:02:57 -0700155
156 out.startTag(null, TAG_ROOT);
157
Makoto Onuki0acbb142016-03-22 17:02:57 -0700158 ShortcutService.writeAttr(out, ATTR_VERSION, mVersionCode);
Makoto Onuki22fcc682016-05-17 14:52:19 -0700159 ShortcutService.writeAttr(out, ATTR_LAST_UPDATE_TIME, mLastUpdateTime);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700160 ShortcutService.writeAttr(out, ATTR_SHADOW, mIsShadow);
161
162 for (int i = 0; i < mSigHashes.size(); i++) {
163 out.startTag(null, TAG_SIGNATURE);
164 ShortcutService.writeAttr(out, ATTR_SIGNATURE_HASH, Base64.encode(mSigHashes.get(i)));
165 out.endTag(null, TAG_SIGNATURE);
166 }
167 out.endTag(null, TAG_ROOT);
168 }
169
Makoto Onuki2e210c42016-03-30 08:30:36 -0700170 public void loadFromXml(XmlPullParser parser, boolean fromBackup)
Makoto Onuki0acbb142016-03-22 17:02:57 -0700171 throws IOException, XmlPullParserException {
172
Makoto Onuki0acbb142016-03-22 17:02:57 -0700173 final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION);
Makoto Onuki2e210c42016-03-30 08:30:36 -0700174
Makoto Onuki440a1ea2016-07-20 14:21:18 -0700175 final long lastUpdateTime = ShortcutService.parseLongAttribute(
Makoto Onuki22fcc682016-05-17 14:52:19 -0700176 parser, ATTR_LAST_UPDATE_TIME);
177
Makoto Onuki2e210c42016-03-30 08:30:36 -0700178 // When restoring from backup, it's always shadow.
179 final boolean shadow =
180 fromBackup || ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700181
182 final ArrayList<byte[]> hashes = new ArrayList<>();
183
Makoto Onuki0acbb142016-03-22 17:02:57 -0700184 final int outerDepth = parser.getDepth();
185 int type;
186 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
187 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
188 if (type != XmlPullParser.START_TAG) {
189 continue;
190 }
191 final int depth = parser.getDepth();
192 final String tag = parser.getName();
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700193
194 if (depth == outerDepth + 1) {
195 switch (tag) {
196 case TAG_SIGNATURE: {
197 final String hash = ShortcutService.parseStringAttribute(
198 parser, ATTR_SIGNATURE_HASH);
199 hashes.add(Base64.decode(hash.getBytes()));
200 continue;
201 }
Makoto Onuki0acbb142016-03-22 17:02:57 -0700202 }
203 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700204 ShortcutService.warnForInvalidTag(depth, tag);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700205 }
Makoto Onuki2e210c42016-03-30 08:30:36 -0700206
207 // Successfully loaded; replace the feilds.
208 mVersionCode = versionCode;
Makoto Onuki22fcc682016-05-17 14:52:19 -0700209 mLastUpdateTime = lastUpdateTime;
Makoto Onuki2e210c42016-03-30 08:30:36 -0700210 mIsShadow = shadow;
211 mSigHashes = hashes;
Makoto Onuki0acbb142016-03-22 17:02:57 -0700212 }
213
Makoto Onukic51b2872016-05-04 15:24:50 -0700214 public void dump(PrintWriter pw, String prefix) {
Makoto Onuki0acbb142016-03-22 17:02:57 -0700215 pw.println();
216
217 pw.print(prefix);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700218 pw.println("PackageInfo:");
Makoto Onukid99c6f02016-03-28 11:02:54 -0700219
220 pw.print(prefix);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700221 pw.print(" IsShadow: ");
222 pw.print(mIsShadow);
223 pw.println();
224
225 pw.print(prefix);
226 pw.print(" Version: ");
227 pw.print(mVersionCode);
228 pw.println();
229
Makoto Onuki22fcc682016-05-17 14:52:19 -0700230 pw.print(prefix);
231 pw.print(" Last package update time: ");
232 pw.print(mLastUpdateTime);
233 pw.println();
234
Makoto Onuki0acbb142016-03-22 17:02:57 -0700235 for (int i = 0; i < mSigHashes.size(); i++) {
236 pw.print(prefix);
237 pw.print(" ");
238 pw.print("SigHash: ");
239 pw.println(HexEncoding.encode(mSigHashes.get(i)));
240 }
241 }
242}