blob: 5f706b83271e11a9357dd79d4301c8352b87d5b5 [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 Onuki0acbb142016-03-22 17:02:57 -070018import android.annotation.UserIdInt;
Makoto Onuki0acbb142016-03-22 17:02:57 -070019import android.content.pm.PackageInfo;
Makoto Onuki0acbb142016-03-22 17:02:57 -070020import android.util.Slog;
21
Makoto Onuki9da23fc2016-03-29 11:14:42 -070022import com.android.server.backup.BackupUtils;
Makoto Onuki0acbb142016-03-22 17:02:57 -070023
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;
Makoto Onuki0acbb142016-03-22 17:02:57 -070033import java.util.ArrayList;
Makoto Onuki0acbb142016-03-22 17:02:57 -070034
35/**
36 * Package information used by {@link android.content.pm.ShortcutManager} for backup / restore.
Makoto Onuki0acbb142016-03-22 17:02:57 -070037 */
Makoto Onuki9da23fc2016-03-29 11:14:42 -070038class ShortcutPackageInfo {
Makoto Onuki0acbb142016-03-22 17:02:57 -070039 private static final String TAG = ShortcutService.TAG;
40
41 static final String TAG_ROOT = "package-info";
Makoto Onuki0acbb142016-03-22 17:02:57 -070042 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 Onuki0acbb142016-03-22 17:02:57 -070048 /**
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 Onuki9da23fc2016-03-29 11:14:42 -070056 private ShortcutPackageInfo(int versionCode, ArrayList<byte[]> sigHashes, boolean isShadow) {
Makoto Onuki0acbb142016-03-22 17:02:57 -070057 mVersionCode = versionCode;
58 mIsShadow = isShadow;
59 mSigHashes = sigHashes;
Makoto Onuki0acbb142016-03-22 17:02:57 -070060 }
61
Makoto Onuki9da23fc2016-03-29 11:14:42 -070062 public static ShortcutPackageInfo newEmpty() {
63 return new ShortcutPackageInfo(0, new ArrayList<>(0), /* isShadow */ false);
Makoto Onukid99c6f02016-03-28 11:02:54 -070064 }
65
Makoto Onuki0acbb142016-03-22 17:02:57 -070066 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 Onuki0acbb142016-03-22 17:02:57 -070082 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 Onuki9da23fc2016-03-29 11:14:42 -070088 if (!BackupUtils.signaturesMatch(mSigHashes, target)) {
Makoto Onuki0acbb142016-03-22 17:02:57 -070089 Slog.w(TAG, "Package signature mismtach");
90 return false;
91 }
92 return true;
93 }
94
95 public static ShortcutPackageInfo generateForInstalledPackage(
Makoto Onuki9da23fc2016-03-29 11:14:42 -070096 ShortcutService s, String packageName, @UserIdInt int packageUserId) {
97 final PackageInfo pi = s.getPackageInfoWithSignatures(packageName, packageUserId);
Makoto Onuki0acbb142016-03-22 17:02:57 -070098 if (pi.signatures == null || pi.signatures.length == 0) {
99 Slog.e(TAG, "Can't get signatures: package=" + packageName);
100 return null;
101 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700102 final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.versionCode,
103 BackupUtils.hashSignatureArray(pi.signatures), /* shadow=*/ false);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700104
105 return ret;
106 }
107
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700108 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 Onuki0acbb142016-03-22 17:02:57 -0700112 if (pi == null) {
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700113 Slog.w(TAG, "Package not found: " + pkg.getPackageName());
Makoto Onuki0acbb142016-03-22 17:02:57 -0700114 return;
115 }
116 mVersionCode = pi.versionCode;
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700117 mSigHashes = BackupUtils.hashSignatureArray(pi.signatures);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700118 }
119
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700120 public void saveToXml(XmlSerializer out) throws IOException {
Makoto Onuki0acbb142016-03-22 17:02:57 -0700121
122 out.startTag(null, TAG_ROOT);
123
Makoto Onuki0acbb142016-03-22 17:02:57 -0700124 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 Onuki9da23fc2016-03-29 11:14:42 -0700135 public static ShortcutPackageInfo loadFromXml(XmlPullParser parser)
Makoto Onuki0acbb142016-03-22 17:02:57 -0700136 throws IOException, XmlPullParserException {
137
Makoto Onuki0acbb142016-03-22 17:02:57 -0700138 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 Onuki9da23fc2016-03-29 11:14:42 -0700153
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 Onuki0acbb142016-03-22 17:02:57 -0700162 }
163 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700164 ShortcutService.warnForInvalidTag(depth, tag);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700165 }
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700166 return new ShortcutPackageInfo(versionCode, hashes, shadow);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700167 }
168
169 public void dump(ShortcutService s, PrintWriter pw, String prefix) {
170 pw.println();
171
172 pw.print(prefix);
Makoto Onuki9da23fc2016-03-29 11:14:42 -0700173 pw.println("PackageInfo:");
Makoto Onukid99c6f02016-03-28 11:02:54 -0700174
175 pw.print(prefix);
Makoto Onuki0acbb142016-03-22 17:02:57 -0700176 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}