1 /*
2  * Copyright (C) 2011 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 
17 package com.android.server.pm;
18 
19 import com.android.internal.util.XmlUtils;
20 
21 import org.xmlpull.v1.XmlPullParser;
22 import org.xmlpull.v1.XmlPullParserException;
23 import org.xmlpull.v1.XmlSerializer;
24 
25 import android.content.pm.Signature;
26 import android.util.Log;
27 
28 import java.io.IOException;
29 import java.util.ArrayList;
30 
31 class PackageSignatures {
32     Signature[] mSignatures;
33 
PackageSignatures(PackageSignatures orig)34     PackageSignatures(PackageSignatures orig) {
35         if (orig != null && orig.mSignatures != null) {
36             mSignatures = orig.mSignatures.clone();
37         }
38     }
39 
PackageSignatures(Signature[] sigs)40     PackageSignatures(Signature[] sigs) {
41         assignSignatures(sigs);
42     }
43 
PackageSignatures()44     PackageSignatures() {
45     }
46 
writeXml(XmlSerializer serializer, String tagName, ArrayList<Signature> pastSignatures)47     void writeXml(XmlSerializer serializer, String tagName,
48             ArrayList<Signature> pastSignatures) throws IOException {
49         if (mSignatures == null) {
50             return;
51         }
52         serializer.startTag(null, tagName);
53         serializer.attribute(null, "count",
54                 Integer.toString(mSignatures.length));
55         for (int i=0; i<mSignatures.length; i++) {
56             serializer.startTag(null, "cert");
57             final Signature sig = mSignatures[i];
58             final int sigHash = sig.hashCode();
59             final int numPast = pastSignatures.size();
60             int j;
61             for (j=0; j<numPast; j++) {
62                 Signature pastSig = pastSignatures.get(j);
63                 if (pastSig.hashCode() == sigHash && pastSig.equals(sig)) {
64                     serializer.attribute(null, "index", Integer.toString(j));
65                     break;
66                 }
67             }
68             if (j >= numPast) {
69                 pastSignatures.add(sig);
70                 serializer.attribute(null, "index", Integer.toString(numPast));
71                 serializer.attribute(null, "key", sig.toCharsString());
72             }
73             serializer.endTag(null, "cert");
74         }
75         serializer.endTag(null, tagName);
76     }
77 
readXml(XmlPullParser parser, ArrayList<Signature> pastSignatures)78     void readXml(XmlPullParser parser, ArrayList<Signature> pastSignatures)
79             throws IOException, XmlPullParserException {
80         String countStr = parser.getAttributeValue(null, "count");
81         if (countStr == null) {
82             PackageManagerService.reportSettingsProblem(Log.WARN,
83                     "Error in package manager settings: <signatures> has"
84                        + " no count at " + parser.getPositionDescription());
85             XmlUtils.skipCurrentTag(parser);
86         }
87         final int count = Integer.parseInt(countStr);
88         mSignatures = new Signature[count];
89         int pos = 0;
90 
91         int outerDepth = parser.getDepth();
92         int type;
93         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
94                && (type != XmlPullParser.END_TAG
95                        || parser.getDepth() > outerDepth)) {
96             if (type == XmlPullParser.END_TAG
97                     || type == XmlPullParser.TEXT) {
98                 continue;
99             }
100 
101             String tagName = parser.getName();
102             if (tagName.equals("cert")) {
103                 if (pos < count) {
104                     String index = parser.getAttributeValue(null, "index");
105                     if (index != null) {
106                         try {
107                             int idx = Integer.parseInt(index);
108                             String key = parser.getAttributeValue(null, "key");
109                             if (key == null) {
110                                 if (idx >= 0 && idx < pastSignatures.size()) {
111                                     Signature sig = pastSignatures.get(idx);
112                                     if (sig != null) {
113                                         mSignatures[pos] = pastSignatures.get(idx);
114                                         pos++;
115                                     } else {
116                                         PackageManagerService.reportSettingsProblem(Log.WARN,
117                                                 "Error in package manager settings: <cert> "
118                                                    + "index " + index + " is not defined at "
119                                                    + parser.getPositionDescription());
120                                     }
121                                 } else {
122                                     PackageManagerService.reportSettingsProblem(Log.WARN,
123                                             "Error in package manager settings: <cert> "
124                                                + "index " + index + " is out of bounds at "
125                                                + parser.getPositionDescription());
126                                 }
127                             } else {
128                                 while (pastSignatures.size() <= idx) {
129                                     pastSignatures.add(null);
130                                 }
131                                 Signature sig = new Signature(key);
132                                 pastSignatures.set(idx, sig);
133                                 mSignatures[pos] = sig;
134                                 pos++;
135                             }
136                         } catch (NumberFormatException e) {
137                             PackageManagerService.reportSettingsProblem(Log.WARN,
138                                     "Error in package manager settings: <cert> "
139                                        + "index " + index + " is not a number at "
140                                        + parser.getPositionDescription());
141                         } catch (IllegalArgumentException e) {
142                             PackageManagerService.reportSettingsProblem(Log.WARN,
143                                     "Error in package manager settings: <cert> "
144                                        + "index " + index + " has an invalid signature at "
145                                        + parser.getPositionDescription() + ": "
146                                        + e.getMessage());
147                         }
148                     } else {
149                         PackageManagerService.reportSettingsProblem(Log.WARN,
150                                 "Error in package manager settings: <cert> has"
151                                    + " no index at " + parser.getPositionDescription());
152                     }
153                 } else {
154                     PackageManagerService.reportSettingsProblem(Log.WARN,
155                             "Error in package manager settings: too "
156                                + "many <cert> tags, expected " + count
157                                + " at " + parser.getPositionDescription());
158                 }
159             } else {
160                 PackageManagerService.reportSettingsProblem(Log.WARN,
161                         "Unknown element under <cert>: "
162                         + parser.getName());
163             }
164             XmlUtils.skipCurrentTag(parser);
165         }
166 
167         if (pos < count) {
168             // Should never happen -- there is an error in the written
169             // settings -- but if it does we don't want to generate
170             // a bad array.
171             Signature[] newSigs = new Signature[pos];
172             System.arraycopy(mSignatures, 0, newSigs, 0, pos);
173             mSignatures = newSigs;
174         }
175     }
176 
assignSignatures(Signature[] sigs)177     void assignSignatures(Signature[] sigs) {
178         if (sigs == null) {
179             mSignatures = null;
180             return;
181         }
182         mSignatures = new Signature[sigs.length];
183         for (int i=0; i<sigs.length; i++) {
184             mSignatures[i] = sigs[i];
185         }
186     }
187 
188     @Override
toString()189     public String toString() {
190         StringBuffer buf = new StringBuffer(128);
191         buf.append("PackageSignatures{");
192         buf.append(Integer.toHexString(System.identityHashCode(this)));
193         buf.append(" [");
194         if (mSignatures != null) {
195             for (int i=0; i<mSignatures.length; i++) {
196                 if (i > 0) buf.append(", ");
197                 buf.append(Integer.toHexString(
198                         mSignatures[i].hashCode()));
199             }
200         }
201         buf.append("]}");
202         return buf.toString();
203     }
204 }