blob: 390f76968e7c71eefb983adc0495ec0cbf0412cb [file] [log] [blame]
Winson022e7072020-01-28 10:52:58 -08001/*
2 * Copyright (C) 2020 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
17package android.content.pm.parsing.component;
18
19import android.annotation.NonNull;
20import android.content.Intent;
21import android.content.IntentFilter;
22import android.content.pm.PackageParser;
23import android.content.pm.parsing.ParsingPackage;
24import android.content.pm.parsing.ParsingPackageUtils;
25import android.content.pm.parsing.ParsingUtils;
26import android.content.pm.parsing.result.ParseInput;
27import android.content.pm.parsing.result.ParseResult;
28import android.content.res.Resources;
29import android.content.res.TypedArray;
30import android.content.res.XmlResourceParser;
31import android.os.PatternMatcher;
Winson022e7072020-01-28 10:52:58 -080032import android.util.Slog;
33import android.util.TypedValue;
34
35import com.android.internal.R;
36
37import org.xmlpull.v1.XmlPullParser;
38import org.xmlpull.v1.XmlPullParserException;
39
40import java.io.IOException;
41import java.util.Iterator;
42
43/** @hide */
44public class ParsedIntentInfoUtils {
45
46 private static final String TAG = ParsingPackageUtils.TAG;
47
48 @NonNull
49 public static ParseResult<ParsedIntentInfo> parseIntentInfo(String className,
50 ParsingPackage pkg, Resources res, XmlResourceParser parser, boolean allowGlobs,
51 boolean allowAutoVerify, ParseInput input)
52 throws XmlPullParserException, IOException {
53 ParsedIntentInfo intentInfo = new ParsedIntentInfo();
Winsonf00c7552020-01-28 12:52:01 -080054 TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestIntentFilter);
55 try {
Winson022e7072020-01-28 10:52:58 -080056 intentInfo.setPriority(sa.getInt(R.styleable.AndroidManifestIntentFilter_priority, 0));
57 intentInfo.setOrder(sa.getInt(R.styleable.AndroidManifestIntentFilter_order, 0));
58
59 TypedValue v = sa.peekValue(R.styleable.AndroidManifestIntentFilter_label);
60 if (v != null) {
61 intentInfo.labelRes = v.resourceId;
62 if (v.resourceId == 0) {
63 intentInfo.nonLocalizedLabel = v.coerceToString();
64 }
65 }
66
67 if (PackageParser.sUseRoundIcon) {
68 intentInfo.icon = sa.getResourceId(
69 R.styleable.AndroidManifestIntentFilter_roundIcon, 0);
70 }
71
72 if (intentInfo.icon == 0) {
73 intentInfo.icon = sa.getResourceId(R.styleable.AndroidManifestIntentFilter_icon, 0);
74 }
75
76 if (allowAutoVerify) {
77 intentInfo.setAutoVerify(sa.getBoolean(
78 R.styleable.AndroidManifestIntentFilter_autoVerify,
79 false));
80 }
Winsonf00c7552020-01-28 12:52:01 -080081 } finally {
82 sa.recycle();
Winson022e7072020-01-28 10:52:58 -080083 }
84 final int depth = parser.getDepth();
85 int type;
86 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
87 && (type != XmlPullParser.END_TAG
88 || parser.getDepth() > depth)) {
89 if (type != XmlPullParser.START_TAG) {
90 continue;
91 }
92
93 final ParseResult result;
94 String nodeName = parser.getName();
95 switch (nodeName) {
96 case "action": {
97 String value = parser.getAttributeValue(PackageParser.ANDROID_RESOURCES,
98 "name");
Winson727da642020-03-10 15:25:32 -070099 if (value == null) {
Winson022e7072020-01-28 10:52:58 -0800100 result = input.error("No value supplied for <android:name>");
Winson727da642020-03-10 15:25:32 -0700101 } else if (value.isEmpty()) {
102 intentInfo.addAction(value);
103 // Prior to R, this was not a failure
104 result = input.deferError("No value supplied for <android:name>",
105 ParseInput.DeferredError.EMPTY_INTENT_ACTION_CATEGORY);
Winson022e7072020-01-28 10:52:58 -0800106 } else {
107 intentInfo.addAction(value);
108 result = input.success(null);
109 }
110 break;
111 }
112 case "category": {
113 String value = parser.getAttributeValue(PackageParser.ANDROID_RESOURCES,
114 "name");
Winson727da642020-03-10 15:25:32 -0700115 if (value == null) {
Winson022e7072020-01-28 10:52:58 -0800116 result = input.error("No value supplied for <android:name>");
Winson727da642020-03-10 15:25:32 -0700117 } else if (value.isEmpty()) {
118 intentInfo.addCategory(value);
119 // Prior to R, this was not a failure
120 result = input.deferError("No value supplied for <android:name>",
121 ParseInput.DeferredError.EMPTY_INTENT_ACTION_CATEGORY);
Winson022e7072020-01-28 10:52:58 -0800122 } else {
123 intentInfo.addCategory(value);
124 result = input.success(null);
125 }
126 break;
127 }
128 case "data":
129 result = parseData(intentInfo, res, parser, allowGlobs, input);
130 break;
131 default:
132 result = ParsingUtils.unknownTag("<intent-filter>", pkg, parser, input);
133 break;
134 }
135
136 if (result.isError()) {
137 return input.error(result);
138 }
139 }
140
141 intentInfo.hasDefault = intentInfo.hasCategory(Intent.CATEGORY_DEFAULT);
142
143 if (PackageParser.DEBUG_PARSER) {
144 final StringBuilder cats = new StringBuilder("Intent d=");
145 cats.append(intentInfo.isHasDefault());
146 cats.append(", cat=");
147
148 final Iterator<String> it = intentInfo.categoriesIterator();
149 if (it != null) {
150 while (it.hasNext()) {
151 cats.append(' ');
152 cats.append(it.next());
153 }
154 }
155 Slog.d(TAG, cats.toString());
156 }
157
158 return input.success(intentInfo);
159 }
160
161 @NonNull
Winsonf00c7552020-01-28 12:52:01 -0800162 private static ParseResult<ParsedIntentInfo> parseData(ParsedIntentInfo intentInfo,
Winson022e7072020-01-28 10:52:58 -0800163 Resources resources, XmlResourceParser parser, boolean allowGlobs, ParseInput input) {
Winsonf00c7552020-01-28 12:52:01 -0800164 TypedArray sa = resources.obtainAttributes(parser, R.styleable.AndroidManifestData);
165 try {
Winson022e7072020-01-28 10:52:58 -0800166 String str = sa.getNonConfigurationString(
167 R.styleable.AndroidManifestData_mimeType, 0);
168 if (str != null) {
169 try {
170 intentInfo.addDataType(str);
171 } catch (IntentFilter.MalformedMimeTypeException e) {
172 return input.error(e.toString());
173 }
174 }
175
176 str = sa.getNonConfigurationString(
Winsonf00c7552020-01-28 12:52:01 -0800177 R.styleable.AndroidManifestData_mimeGroup, 0);
178 if (str != null) {
179 intentInfo.addMimeGroup(str);
180 }
181
182 str = sa.getNonConfigurationString(
Winson022e7072020-01-28 10:52:58 -0800183 R.styleable.AndroidManifestData_scheme, 0);
184 if (str != null) {
185 intentInfo.addDataScheme(str);
186 }
187
188 str = sa.getNonConfigurationString(
189 R.styleable.AndroidManifestData_ssp, 0);
190 if (str != null) {
191 intentInfo.addDataSchemeSpecificPart(str,
192 PatternMatcher.PATTERN_LITERAL);
193 }
194
195 str = sa.getNonConfigurationString(
196 R.styleable.AndroidManifestData_sspPrefix, 0);
197 if (str != null) {
198 intentInfo.addDataSchemeSpecificPart(str,
199 PatternMatcher.PATTERN_PREFIX);
200 }
201
202 str = sa.getNonConfigurationString(
203 R.styleable.AndroidManifestData_sspPattern, 0);
204 if (str != null) {
205 if (!allowGlobs) {
206 return input.error(
207 "sspPattern not allowed here; ssp must be literal");
208 }
209 intentInfo.addDataSchemeSpecificPart(str,
210 PatternMatcher.PATTERN_SIMPLE_GLOB);
211 }
212
213 String host = sa.getNonConfigurationString(
214 R.styleable.AndroidManifestData_host, 0);
215 String port = sa.getNonConfigurationString(
216 R.styleable.AndroidManifestData_port, 0);
217 if (host != null) {
218 intentInfo.addDataAuthority(host, port);
219 }
220
221 str = sa.getNonConfigurationString(
222 R.styleable.AndroidManifestData_path, 0);
223 if (str != null) {
224 intentInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
225 }
226
227 str = sa.getNonConfigurationString(
228 R.styleable.AndroidManifestData_pathPrefix, 0);
229 if (str != null) {
230 intentInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
231 }
232
233 str = sa.getNonConfigurationString(
234 R.styleable.AndroidManifestData_pathPattern, 0);
235 if (str != null) {
236 if (!allowGlobs) {
237 return input.error(
238 "pathPattern not allowed here; path must be literal");
239 }
240 intentInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
241 }
242
243 str = sa.getNonConfigurationString(
244 R.styleable.AndroidManifestData_pathAdvancedPattern, 0);
245 if (str != null) {
246 if (!allowGlobs) {
247 return input.error(
248 "pathAdvancedPattern not allowed here; path must be literal");
249 }
250 intentInfo.addDataPath(str, PatternMatcher.PATTERN_ADVANCED_GLOB);
251 }
252
253 return input.success(null);
Winsonf00c7552020-01-28 12:52:01 -0800254 } finally {
255 sa.recycle();
Winson022e7072020-01-28 10:52:58 -0800256 }
257 }
258}