blob: 595685729a0cea6534e3cfee5f066950e5fd60f1 [file] [log] [blame]
Winson14ff7172019-10-23 10:42:27 -07001/*
2 * Copyright (C) 2019 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;
18
19import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
20import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
21import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
22import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
23import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
24import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
25
26import android.annotation.CallSuper;
Philip P. Moltmann9046d822019-12-13 15:59:49 -080027import android.annotation.NonNull;
28import android.annotation.Nullable;
29import android.annotation.StringRes;
Winson14ff7172019-10-23 10:42:27 -070030import android.annotation.UnsupportedAppUsage;
31import android.app.ActivityTaskManager;
32import android.content.ComponentName;
33import android.content.Intent;
34import android.content.IntentFilter;
35import android.content.pm.ActivityInfo;
36import android.content.pm.ApplicationInfo;
37import android.content.pm.PackageManager;
38import android.content.pm.PackageParser;
39import android.content.pm.PathPermission;
40import android.content.pm.PermissionInfo;
41import android.content.pm.ProviderInfo;
42import android.content.pm.ServiceInfo;
43import android.content.res.Configuration;
44import android.content.res.Resources;
45import android.content.res.TypedArray;
46import android.content.res.XmlResourceParser;
47import android.os.Build;
48import android.os.Bundle;
49import android.os.Parcel;
50import android.os.Parcelable;
51import android.os.PatternMatcher;
52import android.text.TextUtils;
Philip P. Moltmann9046d822019-12-13 15:59:49 -080053import android.util.ArraySet;
Winson14ff7172019-10-23 10:42:27 -070054import android.util.AttributeSet;
55import android.util.Log;
56import android.util.Slog;
Winson14ff7172019-10-23 10:42:27 -070057import android.util.TypedValue;
58import android.view.Gravity;
59
60import com.android.internal.R;
Philip P. Moltmann9046d822019-12-13 15:59:49 -080061import com.android.internal.util.DataClass;
Winson14ff7172019-10-23 10:42:27 -070062import com.android.internal.util.XmlUtils;
63
64import org.xmlpull.v1.XmlPullParser;
65import org.xmlpull.v1.XmlPullParserException;
66
67import java.io.IOException;
68import java.lang.reflect.Constructor;
69import java.util.ArrayList;
Philip P. Moltmann9046d822019-12-13 15:59:49 -080070import java.util.Collections;
Winson14ff7172019-10-23 10:42:27 -070071import java.util.Iterator;
72import java.util.List;
73import java.util.Objects;
74
75/**
76 * TODO(b/135203078): Move the inner classes out to separate files.
77 * TODO(b/135203078): Expose inner classes as immutable through interface methods.
78 *
79 * @hide
80 */
81public class ComponentParseUtils {
82
83 private static final String TAG = ApkParseUtils.TAG;
84
85 // TODO(b/135203078): None of this class's subclasses do anything. Remove in favor of base?
86 public static class ParsedIntentInfo extends IntentFilter {
87
88 /**
89 * <p>
90 * Implementation note: The serialized form for the intent list also contains the name
91 * of the concrete class that's stored in the list, and assumes that every element of the
92 * list is of the same type. This is very similar to the original parcelable mechanism.
93 * We cannot use that directly because IntentInfo extends IntentFilter, which is parcelable
94 * and is public API. It also declares Parcelable related methods as final which means
95 * we can't extend them. The approach of using composition instead of inheritance leads to
96 * a large set of cascading changes in the PackageManagerService, which seem undesirable.
97 *
98 * <p>
99 * <b>WARNING: </b> The list of objects returned by this function might need to be fixed up
100 * to make sure their owner fields are consistent. See {@code fixupOwner}.
101 */
102 public static void writeIntentsList(List<? extends ParsedIntentInfo> list, Parcel out,
103 int flags) {
104 if (list == null) {
105 out.writeInt(-1);
106 return;
107 }
108
109 final int size = list.size();
110 out.writeInt(size);
111
112 // Don't bother writing the component name if the list is empty.
113 if (size > 0) {
114 ParsedIntentInfo info = list.get(0);
115 out.writeString(info.getClass().getName());
116
117 for (int i = 0; i < size; i++) {
118 list.get(i).writeIntentInfoToParcel(out, flags);
119 }
120 }
121 }
122
123 public static <T extends ParsedIntentInfo> ArrayList<T> createIntentsList(Parcel in) {
124 int size = in.readInt();
125 if (size == -1) {
126 return null;
127 }
128
129 if (size == 0) {
130 return new ArrayList<>(0);
131 }
132
133 String className = in.readString();
134 final ArrayList<T> intentsList;
135 try {
136 final Class<T> cls = (Class<T>) Class.forName(className);
137 final Constructor<T> cons = cls.getConstructor(Parcel.class);
138
139 intentsList = new ArrayList<>(size);
140 for (int i = 0; i < size; ++i) {
141 intentsList.add(cons.newInstance(in));
142 }
143 } catch (ReflectiveOperationException ree) {
144 throw new AssertionError("Unable to construct intent list for: "
145 + className, ree);
146 }
147
148 return intentsList;
149 }
150
151 protected String packageName;
152 protected final String className;
153
154 public boolean hasDefault;
155 public int labelRes;
156 public CharSequence nonLocalizedLabel;
157 public int icon;
158
159 protected List<String> rawDataTypes;
160
161 public void addRawDataType(String dataType) throws MalformedMimeTypeException {
162 if (rawDataTypes == null) {
163 rawDataTypes = new ArrayList<>();
164 }
165
166 rawDataTypes.add(dataType);
167 addDataType(dataType);
168 }
169
170 public ParsedIntentInfo(String packageName, String className) {
171 this.packageName = packageName;
172 this.className = className;
173 }
174
175 public ParsedIntentInfo(Parcel in) {
176 super(in);
177 packageName = in.readString();
178 className = in.readString();
179 hasDefault = (in.readInt() == 1);
180 labelRes = in.readInt();
181 nonLocalizedLabel = in.readCharSequence();
182 icon = in.readInt();
183 }
184
185 public void writeIntentInfoToParcel(Parcel dest, int flags) {
186 super.writeToParcel(dest, flags);
187 dest.writeString(packageName);
188 dest.writeString(className);
189 dest.writeInt(hasDefault ? 1 : 0);
190 dest.writeInt(labelRes);
191 dest.writeCharSequence(nonLocalizedLabel);
192 dest.writeInt(icon);
193 }
194
195 public String getPackageName() {
196 return packageName;
197 }
198
199 public String getClassName() {
200 return className;
201 }
202 }
203
204 public static class ParsedActivityIntentInfo extends ParsedIntentInfo {
205
206 public ParsedActivityIntentInfo(String packageName, String className) {
207 super(packageName, className);
208 }
209
210 public ParsedActivityIntentInfo(Parcel in) {
211 super(in);
212 }
213
214 public static final Creator<ParsedActivityIntentInfo> CREATOR =
215 new Creator<ParsedActivityIntentInfo>() {
216 @Override
217 public ParsedActivityIntentInfo createFromParcel(Parcel source) {
218 return new ParsedActivityIntentInfo(source);
219 }
220
221 @Override
222 public ParsedActivityIntentInfo[] newArray(int size) {
223 return new ParsedActivityIntentInfo[size];
224 }
225 };
226 }
227
228 public static class ParsedServiceIntentInfo extends ParsedIntentInfo {
229
230 public ParsedServiceIntentInfo(String packageName, String className) {
231 super(packageName, className);
232 }
233
234 public ParsedServiceIntentInfo(Parcel in) {
235 super(in);
236 }
237
238 public static final Creator<ParsedServiceIntentInfo> CREATOR =
239 new Creator<ParsedServiceIntentInfo>() {
240 @Override
241 public ParsedServiceIntentInfo createFromParcel(Parcel source) {
242 return new ParsedServiceIntentInfo(source);
243 }
244
245 @Override
246 public ParsedServiceIntentInfo[] newArray(int size) {
247 return new ParsedServiceIntentInfo[size];
248 }
249 };
250 }
251
252 public static class ParsedProviderIntentInfo extends ParsedIntentInfo {
253
254 public ParsedProviderIntentInfo(String packageName, String className) {
255 super(packageName, className);
256 }
257
258 public ParsedProviderIntentInfo(Parcel in) {
259 super(in);
260 }
261
262 public static final Creator<ParsedProviderIntentInfo> CREATOR =
263 new Creator<ParsedProviderIntentInfo>() {
264 @Override
265 public ParsedProviderIntentInfo createFromParcel(Parcel source) {
266 return new ParsedProviderIntentInfo(source);
267 }
268
269 @Override
270 public ParsedProviderIntentInfo[] newArray(int size) {
271 return new ParsedProviderIntentInfo[size];
272 }
273 };
274 }
275
276 public static class ParsedQueriesIntentInfo extends ParsedIntentInfo {
277
278 public ParsedQueriesIntentInfo(String packageName, String className) {
279 super(packageName, className);
280 }
281
282 public ParsedQueriesIntentInfo(Parcel in) {
283 super(in);
284 }
285
286 public static final Creator<ParsedQueriesIntentInfo> CREATOR =
287 new Creator<ParsedQueriesIntentInfo>() {
288 @Override
289 public ParsedQueriesIntentInfo createFromParcel(Parcel source) {
290 return new ParsedQueriesIntentInfo(source);
291 }
292
293 @Override
294 public ParsedQueriesIntentInfo[] newArray(int size) {
295 return new ParsedQueriesIntentInfo[size];
296 }
297 };
298 }
299
300 public static class ParsedComponent<IntentInfoType extends ParsedIntentInfo> implements
301 Parcelable {
302
303 // TODO(b/135203078): Replace with "name", as not all usages are an actual class
304 public String className;
305 public int icon;
306 public int labelRes;
307 public CharSequence nonLocalizedLabel;
308 public int logo;
309 public int banner;
310
311 public int descriptionRes;
312
313 // TODO(b/135203078): Make subclass that contains these fields only for the necessary
314 // subtypes
315 protected boolean enabled = true;
316 protected boolean directBootAware;
317 public int flags;
318
319 private String packageName;
320 private String splitName;
321
322 // TODO(b/135203078): Make nullable
323 public List<IntentInfoType> intents = new ArrayList<>();
324
325 private transient ComponentName componentName;
326
327 protected Bundle metaData;
328
329 public void setSplitName(String splitName) {
330 this.splitName = splitName;
331 }
332
333 public String getSplitName() {
334 return splitName;
335 }
336
337 @CallSuper
338 public void setPackageName(String packageName) {
339 this.packageName = packageName;
340 this.componentName = null;
341 }
342
343 void setPackageNameInternal(String packageName) {
344 this.packageName = packageName;
345 this.componentName = null;
346 }
347
Winson655a5b92019-10-23 10:49:32 -0700348 public void setEnabled(boolean enabled) {
349 this.enabled = enabled;
350 }
351
Winson14ff7172019-10-23 10:42:27 -0700352 public String getPackageName() {
353 return packageName;
354 }
355
356 public final boolean isDirectBootAware() {
357 return directBootAware;
358 }
359
360 public final boolean isEnabled() {
361 return enabled;
362 }
363
364 public final String getName() {
365 return className;
366 }
367
368 public final Bundle getMetaData() {
369 return metaData;
370 }
371
372 @UnsupportedAppUsage
373 public ComponentName getComponentName() {
374 if (componentName != null) {
375 return componentName;
376 }
377 if (className != null) {
378 componentName = new ComponentName(getPackageName(),
379 className);
380 }
381 return componentName;
382 }
383
384 public void setFrom(ParsedComponent other) {
385 this.metaData = other.metaData;
386 this.className = other.className;
387 this.icon = other.icon;
388 this.labelRes = other.labelRes;
389 this.nonLocalizedLabel = other.nonLocalizedLabel;
390 this.logo = other.logo;
391 this.banner = other.banner;
392
393 this.descriptionRes = other.descriptionRes;
394
395 this.enabled = other.enabled;
396 this.directBootAware = other.directBootAware;
397 this.flags = other.flags;
398
399 this.setPackageName(other.packageName);
400 this.setSplitName(other.getSplitName());
401 }
402
403 @Override
404 public int describeContents() {
405 return 0;
406 }
407
408 @Override
409 public void writeToParcel(Parcel dest, int flags) {
410 dest.writeString(this.className);
411 dest.writeInt(this.icon);
412 dest.writeInt(this.labelRes);
413 dest.writeCharSequence(this.nonLocalizedLabel);
414 dest.writeInt(this.logo);
415 dest.writeInt(this.banner);
416 dest.writeInt(this.descriptionRes);
417 dest.writeBoolean(this.enabled);
418 dest.writeBoolean(this.directBootAware);
419 dest.writeInt(this.flags);
420 dest.writeString(this.packageName);
421 dest.writeString(this.splitName);
422 ParsedIntentInfo.writeIntentsList(this.intents, dest, flags);
423 dest.writeBundle(this.metaData);
424 }
425
426 public ParsedComponent() {
427 }
428
429 protected ParsedComponent(Parcel in) {
430 // We use the boot classloader for all classes that we load.
431 final ClassLoader boot = Object.class.getClassLoader();
432 this.className = in.readString();
433 this.icon = in.readInt();
434 this.labelRes = in.readInt();
435 this.nonLocalizedLabel = in.readCharSequence();
436 this.logo = in.readInt();
437 this.banner = in.readInt();
438 this.descriptionRes = in.readInt();
439 this.enabled = in.readByte() != 0;
440 this.directBootAware = in.readByte() != 0;
441 this.flags = in.readInt();
442 this.packageName = in.readString();
443 this.splitName = in.readString();
444 this.intents = ParsedIntentInfo.createIntentsList(in);
445 this.metaData = in.readBundle(boot);
446 }
447 }
448
449 // TODO(b/135203078): Document this. Maybe split out ParsedComponent to be actual components
450 // that can have their own processes, rather than something like permission which cannot.
451 public static class ParsedMainComponent<IntentInfoType extends ParsedIntentInfo> extends
452 ParsedComponent<IntentInfoType> {
453
454 private String processName;
455 private String permission;
456
457 public void setProcessName(String appProcessName, String processName) {
458 // TODO(b/135203078): Is this even necessary anymore?
459 this.processName = TextUtils.safeIntern(
460 processName == null ? appProcessName : processName);
461 }
462
463 public String getProcessName() {
464 return processName;
465 }
466
467 public void setPermission(String permission) {
Winson7ef452c2020-01-06 14:12:36 -0800468 // Empty string must be converted to null
469 this.permission = TextUtils.isEmpty(permission) ? null : permission.intern();
Winson14ff7172019-10-23 10:42:27 -0700470 }
471
472 public String getPermission() {
473 return permission;
474 }
475
476 @Override
477 public void setFrom(ParsedComponent other) {
478 super.setFrom(other);
479 if (other instanceof ParsedMainComponent) {
480 ParsedMainComponent otherMainComponent = (ParsedMainComponent) other;
481 this.setProcessName(otherMainComponent.getProcessName(),
482 otherMainComponent.getProcessName());
483 this.setPermission(otherMainComponent.getPermission());
484 }
485 }
486
487 @Override
488 public int describeContents() {
489 return 0;
490 }
491
492 @Override
493 public void writeToParcel(Parcel dest, int flags) {
494 super.writeToParcel(dest, flags);
495 dest.writeString(this.processName);
496 dest.writeString(this.permission);
497 }
498
499 public ParsedMainComponent() {
500 }
501
502 protected ParsedMainComponent(Parcel in) {
503 super(in);
504 this.processName = TextUtils.safeIntern(in.readString());
505 this.permission = TextUtils.safeIntern(in.readString());
506 }
507
508 public static final Creator<ParsedMainComponent> CREATOR =
509 new Creator<ParsedMainComponent>() {
510 @Override
511 public ParsedMainComponent createFromParcel(Parcel source) {
512 return new ParsedMainComponent(source);
513 }
514
515 @Override
516 public ParsedMainComponent[] newArray(int size) {
517 return new ParsedMainComponent[size];
518 }
519 };
520 }
521
522 public static class ParsedActivity extends ParsedMainComponent<ParsedActivityIntentInfo>
523 implements Parcelable {
524
525 public boolean exported;
526 public int theme;
527 public int uiOptions;
528
529 public String targetActivity;
530
531 public String parentActivityName;
532 public String taskAffinity;
533 public int privateFlags;
534
535 public int launchMode;
536 public int documentLaunchMode;
537 public int maxRecents;
538 public int configChanges;
539 public int softInputMode;
540 public int persistableMode;
541 public int lockTaskLaunchMode;
542
543 public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
544 public int resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
545
546 public float maxAspectRatio;
547 public boolean hasMaxAspectRatio;
548
549 public float minAspectRatio;
550 public boolean hasMinAspectRatio;
551
552 public String requestedVrComponent;
553 public int rotationAnimation = -1;
554 public int colorMode;
555 public int order;
556
557 public ActivityInfo.WindowLayout windowLayout;
558
559 @Override
560 public void setPackageName(String packageName) {
561 super.setPackageName(packageName);
562 for (ParsedIntentInfo intent : this.intents) {
563 intent.packageName = packageName;
564 }
565 }
566
567 public boolean hasMaxAspectRatio() {
568 return hasMaxAspectRatio;
569 }
570
571 public boolean hasMinAspectRatio() {
572 return hasMinAspectRatio;
573 }
574
575 public void setMaxAspectRatio(int resizeMode, float maxAspectRatio) {
576 if (resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE
577 || resizeMode == ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
578 // Resizeable activities can be put in any aspect ratio.
579 return;
580 }
581
582 if (maxAspectRatio < 1.0f && maxAspectRatio != 0) {
583 // Ignore any value lesser than 1.0.
584 return;
585 }
586
587 this.maxAspectRatio = maxAspectRatio;
588 hasMaxAspectRatio = true;
589 }
590
591 public void setMinAspectRatio(int resizeMode, float minAspectRatio) {
592 if (resizeMode == RESIZE_MODE_RESIZEABLE
593 || resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
594 // Resizeable activities can be put in any aspect ratio.
595 return;
596 }
597
598 if (minAspectRatio < 1.0f && minAspectRatio != 0) {
599 // Ignore any value lesser than 1.0.
600 return;
601 }
602
603 this.minAspectRatio = minAspectRatio;
604 hasMinAspectRatio = true;
605 }
606
607 public void addIntent(ParsedActivityIntentInfo intent) {
608 this.intents.add(intent);
609 }
610
611 @Override
612 public int describeContents() {
613 return 0;
614 }
615
616 @Override
617 public void writeToParcel(Parcel dest, int flags) {
618 super.writeToParcel(dest, flags);
619 dest.writeBoolean(this.exported);
620 dest.writeInt(this.theme);
621 dest.writeInt(this.uiOptions);
622 dest.writeString(this.targetActivity);
623 dest.writeString(this.parentActivityName);
624 dest.writeString(this.taskAffinity);
625 dest.writeInt(this.privateFlags);
626 dest.writeInt(this.launchMode);
627 dest.writeInt(this.documentLaunchMode);
628 dest.writeInt(this.maxRecents);
629 dest.writeInt(this.configChanges);
630 dest.writeInt(this.softInputMode);
631 dest.writeInt(this.persistableMode);
632 dest.writeInt(this.lockTaskLaunchMode);
633 dest.writeInt(this.screenOrientation);
634 dest.writeInt(this.resizeMode);
635 dest.writeFloat(this.maxAspectRatio);
636 dest.writeBoolean(this.hasMaxAspectRatio);
637 dest.writeFloat(this.minAspectRatio);
638 dest.writeBoolean(this.hasMinAspectRatio);
639 dest.writeString(this.requestedVrComponent);
640 dest.writeInt(this.rotationAnimation);
641 dest.writeInt(this.colorMode);
642 dest.writeInt(this.order);
643 dest.writeBundle(this.metaData);
644
645 if (windowLayout != null) {
646 dest.writeInt(1);
647 dest.writeInt(windowLayout.width);
648 dest.writeFloat(windowLayout.widthFraction);
649 dest.writeInt(windowLayout.height);
650 dest.writeFloat(windowLayout.heightFraction);
651 dest.writeInt(windowLayout.gravity);
652 dest.writeInt(windowLayout.minWidth);
653 dest.writeInt(windowLayout.minHeight);
654 } else {
655 dest.writeInt(0);
656 }
657 }
658
659 public ParsedActivity() {
660 }
661
662 protected ParsedActivity(Parcel in) {
663 super(in);
664 this.exported = in.readByte() != 0;
665 this.theme = in.readInt();
666 this.uiOptions = in.readInt();
667 this.targetActivity = in.readString();
668 this.parentActivityName = in.readString();
669 this.taskAffinity = in.readString();
670 this.privateFlags = in.readInt();
671 this.launchMode = in.readInt();
672 this.documentLaunchMode = in.readInt();
673 this.maxRecents = in.readInt();
674 this.configChanges = in.readInt();
675 this.softInputMode = in.readInt();
676 this.persistableMode = in.readInt();
677 this.lockTaskLaunchMode = in.readInt();
678 this.screenOrientation = in.readInt();
679 this.resizeMode = in.readInt();
680 this.maxAspectRatio = in.readFloat();
681 this.hasMaxAspectRatio = in.readByte() != 0;
682 this.minAspectRatio = in.readFloat();
683 this.hasMinAspectRatio = in.readByte() != 0;
684 this.requestedVrComponent = in.readString();
685 this.rotationAnimation = in.readInt();
686 this.colorMode = in.readInt();
687 this.order = in.readInt();
688 this.metaData = in.readBundle();
689 if (in.readInt() == 1) {
690 windowLayout = new ActivityInfo.WindowLayout(in);
691 }
692 }
693
694 public static final Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() {
695 @Override
696 public ParsedActivity createFromParcel(Parcel source) {
697 return new ParsedActivity(source);
698 }
699
700 @Override
701 public ParsedActivity[] newArray(int size) {
702 return new ParsedActivity[size];
703 }
704 };
705 }
706
707 public static class ParsedService extends ParsedMainComponent<ParsedServiceIntentInfo> {
708
709 public boolean exported;
710 public int flags;
711 public int foregroundServiceType;
712 public int order;
713
714 @Override
715 public void setPackageName(String packageName) {
716 super.setPackageName(packageName);
717 for (ParsedIntentInfo intent : this.intents) {
718 intent.packageName = packageName;
719 }
720 }
721
722 @Override
723 public int describeContents() {
724 return 0;
725 }
726
727 @Override
728 public void writeToParcel(Parcel dest, int flags) {
729 super.writeToParcel(dest, flags);
730 dest.writeBoolean(this.exported);
731 dest.writeBundle(this.metaData);
732 dest.writeInt(this.flags);
733 dest.writeInt(this.foregroundServiceType);
734 dest.writeInt(this.order);
735 }
736
737 public ParsedService() {
738 }
739
740 protected ParsedService(Parcel in) {
741 super(in);
742 this.exported = in.readByte() != 0;
743 this.metaData = in.readBundle();
744 this.flags = in.readInt();
745 this.foregroundServiceType = in.readInt();
746 this.order = in.readInt();
747 }
748
749 public static final Creator<ParsedService> CREATOR = new Creator<ParsedService>() {
750 @Override
751 public ParsedService createFromParcel(Parcel source) {
752 return new ParsedService(source);
753 }
754
755 @Override
756 public ParsedService[] newArray(int size) {
757 return new ParsedService[size];
758 }
759 };
760 }
761
762 public static class ParsedProvider extends ParsedMainComponent<ParsedProviderIntentInfo> {
763
764 protected boolean exported;
765 protected int flags;
766 protected int order;
767 private String authority;
768 protected boolean isSyncable;
769 private String readPermission;
770 private String writePermission;
771 protected boolean grantUriPermissions;
772 protected boolean forceUriPermissions;
773 protected boolean multiProcess;
774 protected int initOrder;
775 protected PatternMatcher[] uriPermissionPatterns;
776 protected PathPermission[] pathPermissions;
777
Winson2160e0f2019-12-12 18:25:47 -0800778 public ParsedProvider(ParsedProvider other) {
779 this.setFrom(other);
780 }
781
Winson14ff7172019-10-23 10:42:27 -0700782 protected void setFrom(ParsedProvider other) {
783 super.setFrom(other);
784 this.exported = other.exported;
785
786 this.intents.clear();
787 if (other.intents != null) {
788 this.intents.addAll(other.intents);
789 }
790
791 this.flags = other.flags;
792 this.order = other.order;
793 this.setAuthority(other.getAuthority());
794 this.isSyncable = other.isSyncable;
795 this.setReadPermission(other.getReadPermission());
796 this.setWritePermission(other.getWritePermission());
797 this.grantUriPermissions = other.grantUriPermissions;
798 this.forceUriPermissions = other.forceUriPermissions;
799 this.multiProcess = other.multiProcess;
800 this.initOrder = other.initOrder;
801 this.uriPermissionPatterns = other.uriPermissionPatterns;
802 this.pathPermissions = other.pathPermissions;
803 }
804
805 @Override
806 public void setPackageName(String packageName) {
807 super.setPackageName(packageName);
808 for (ParsedIntentInfo intent : this.intents) {
809 intent.packageName = packageName;
810 }
811 }
812
813 public boolean isExported() {
814 return exported;
815 }
816
817 public List<ParsedProviderIntentInfo> getIntents() {
818 return intents;
819 }
820
821 public int getFlags() {
822 return flags;
823 }
824
825 public int getOrder() {
826 return order;
827 }
828
829 public void setAuthority(String authority) {
830 this.authority = TextUtils.safeIntern(authority);
831 }
832
833 public String getAuthority() {
834 return authority;
835 }
836
Winson2160e0f2019-12-12 18:25:47 -0800837 public void setSyncable(boolean isSyncable) {
838 this.isSyncable = isSyncable;
839 }
840
Winson14ff7172019-10-23 10:42:27 -0700841 public boolean isSyncable() {
842 return isSyncable;
843 }
844
845 public void setReadPermission(String readPermission) {
Winson7ef452c2020-01-06 14:12:36 -0800846 // Empty string must be converted to null
847 this.readPermission = TextUtils.isEmpty(readPermission)
848 ? null : readPermission.intern();
Winson14ff7172019-10-23 10:42:27 -0700849 }
850
851 public String getReadPermission() {
852 return readPermission;
853 }
854
855 public void setWritePermission(String writePermission) {
Winson7ef452c2020-01-06 14:12:36 -0800856 // Empty string must be converted to null
857 this.writePermission = TextUtils.isEmpty(writePermission)
858 ? null : writePermission.intern();
Winson14ff7172019-10-23 10:42:27 -0700859 }
860
861 public String getWritePermission() {
862 return writePermission;
863 }
864
865 public boolean isGrantUriPermissions() {
866 return grantUriPermissions;
867 }
868
869 public boolean isForceUriPermissions() {
870 return forceUriPermissions;
871 }
872
873 public boolean isMultiProcess() {
874 return multiProcess;
875 }
876
877 public int getInitOrder() {
878 return initOrder;
879 }
880
881 public PatternMatcher[] getUriPermissionPatterns() {
882 return uriPermissionPatterns;
883 }
884
885 public PathPermission[] getPathPermissions() {
886 return pathPermissions;
887 }
888
889 @Override
890 public int describeContents() {
891 return 0;
892 }
893
894 @Override
895 public void writeToParcel(Parcel dest, int flags) {
896 super.writeToParcel(dest, flags);
897 dest.writeBoolean(this.exported);
898 dest.writeInt(this.flags);
899 dest.writeInt(this.order);
900 dest.writeString(this.authority);
901 dest.writeBoolean(this.isSyncable);
902 dest.writeString(this.readPermission);
903 dest.writeString(this.writePermission);
904 dest.writeBoolean(this.grantUriPermissions);
905 dest.writeBoolean(this.forceUriPermissions);
906 dest.writeBoolean(this.multiProcess);
907 dest.writeInt(this.initOrder);
908 dest.writeTypedArray(this.uriPermissionPatterns, flags);
909 dest.writeTypedArray(this.pathPermissions, flags);
910 }
911
912 public ParsedProvider() {
913 }
914
915 protected ParsedProvider(Parcel in) {
916 super(in);
917 this.exported = in.readByte() != 0;
918 this.flags = in.readInt();
919 this.order = in.readInt();
920 this.authority = TextUtils.safeIntern(in.readString());
921 this.isSyncable = in.readByte() != 0;
922 this.readPermission = TextUtils.safeIntern(in.readString());
923 this.writePermission = TextUtils.safeIntern(in.readString());
924 this.grantUriPermissions = in.readByte() != 0;
925 this.forceUriPermissions = in.readByte() != 0;
926 this.multiProcess = in.readByte() != 0;
927 this.initOrder = in.readInt();
928 this.uriPermissionPatterns = in.createTypedArray(PatternMatcher.CREATOR);
929 this.pathPermissions = in.createTypedArray(PathPermission.CREATOR);
930 }
931
932 public static final Creator<ParsedProvider> CREATOR = new Creator<ParsedProvider>() {
933 @Override
934 public ParsedProvider createFromParcel(Parcel source) {
935 return new ParsedProvider(source);
936 }
937
938 @Override
939 public ParsedProvider[] newArray(int size) {
940 return new ParsedProvider[size];
941 }
942 };
943 }
944
Philip P. Moltmann9046d822019-12-13 15:59:49 -0800945 /**
946 * A {@link android.R.styleable#AndroidManifestFeature &lt;feature&gt;} tag parsed from the
947 * manifest.
948 */
949 // @DataClass verifier is broken, hence comment out for now
950 public static class ParsedFeature implements Parcelable {
Philip P. Moltmanne52bd982020-01-02 15:24:01 -0800951 /** Maximum length of featureId */
952 public static final int MAX_FEATURE_ID_LEN = 50;
953
954 /** Maximum amount of features per package */
955 private static final int MAX_NUM_FEATURES = 1000;
956
Philip P. Moltmann9046d822019-12-13 15:59:49 -0800957 /** Id of the feature */
958 public final @NonNull String id;
959
960 /** User visible label fo the feature */
961 public final @StringRes int label;
962
963 /** Ids of previously declared features this feature inherits from */
964 public final @NonNull List<String> inheritFrom;
965
966 /**
967 * @return Is this set of features a valid combination for a single package?
968 */
969 public static boolean isCombinationValid(@Nullable List<ParsedFeature> features) {
970 if (features == null) {
971 return true;
972 }
973
974 ArraySet<String> featureIds = new ArraySet<>(features.size());
975 ArraySet<String> inheritFromFeatureIds = new ArraySet<>();
976
977 int numFeatures = features.size();
Philip P. Moltmanne52bd982020-01-02 15:24:01 -0800978 if (numFeatures > MAX_NUM_FEATURES) {
979 return false;
980 }
981
Philip P. Moltmann9046d822019-12-13 15:59:49 -0800982 for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
983 boolean wasAdded = featureIds.add(features.get(featureNum).id);
984 if (!wasAdded) {
985 // feature id is not unique
986 return false;
987 }
988 }
989
990 for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
991 ParsedFeature feature = features.get(featureNum);
992
993 int numInheritFrom = feature.inheritFrom.size();
994 for (int inheritFromNum = 0; inheritFromNum < numInheritFrom; inheritFromNum++) {
995 String inheritFrom = feature.inheritFrom.get(inheritFromNum);
996
997 if (featureIds.contains(inheritFrom)) {
998 // Cannot inherit from a feature that is still defined
999 return false;
1000 }
1001
1002 boolean wasAdded = inheritFromFeatureIds.add(inheritFrom);
1003 if (!wasAdded) {
1004 // inheritFrom is not unique
1005 return false;
1006 }
1007 }
1008 }
1009
1010 return true;
1011 }
1012
1013
1014
1015 // Code below generated by codegen v1.0.14.
1016 //
1017 // DO NOT MODIFY!
1018 // CHECKSTYLE:OFF Generated code
1019 //
1020 // To regenerate run:
1021 // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/ComponentParseUtils.java
1022 //
1023 // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
1024 // Settings > Editor > Code Style > Formatter Control
1025 //@formatter:off
1026
1027
1028 /**
1029 * Creates a new ParsedFeature.
1030 *
1031 * @param id
1032 * Id of the feature
1033 * @param label
1034 * User visible label fo the feature (if defined as resource)
1035 * @param inheritFrom
1036 * Ids of previously declared features this feature inherits from
1037 */
1038 @DataClass.Generated.Member
1039 public ParsedFeature(
1040 @NonNull String id,
1041 @StringRes int label,
1042 @NonNull List<String> inheritFrom) {
1043 this.id = id;
1044 com.android.internal.util.AnnotationValidations.validate(
1045 NonNull.class, null, id);
1046 this.label = label;
1047 com.android.internal.util.AnnotationValidations.validate(
1048 StringRes.class, null, label);
1049 this.inheritFrom = inheritFrom;
1050 com.android.internal.util.AnnotationValidations.validate(
1051 NonNull.class, null, inheritFrom);
1052
1053 // onConstructed(); // You can define this method to get a callback
1054 }
1055
1056 @Override
1057 @DataClass.Generated.Member
1058 public void writeToParcel(@NonNull Parcel dest, int flags) {
1059 // You can override field parcelling by defining methods like:
1060 // void parcelFieldName(Parcel dest, int flags) { ... }
1061
1062 dest.writeString(id);
1063 dest.writeInt(label);
1064 dest.writeStringList(inheritFrom);
1065 }
1066
1067 @Override
1068 @DataClass.Generated.Member
1069 public int describeContents() { return 0; }
1070
1071 /** @hide */
1072 @SuppressWarnings({"unchecked", "RedundantCast"})
1073 @DataClass.Generated.Member
1074 protected ParsedFeature(@NonNull Parcel in) {
1075 // You can override field unparcelling by defining methods like:
1076 // static FieldType unparcelFieldName(Parcel in) { ... }
1077
1078 String _id = in.readString();
1079 int _label = in.readInt();
1080 List<String> _inheritFrom = new ArrayList<>();
1081 in.readStringList(_inheritFrom);
1082
1083 this.id = _id;
1084 com.android.internal.util.AnnotationValidations.validate(
1085 NonNull.class, null, id);
1086 this.label = _label;
1087 com.android.internal.util.AnnotationValidations.validate(
1088 StringRes.class, null, label);
1089 this.inheritFrom = _inheritFrom;
1090 com.android.internal.util.AnnotationValidations.validate(
1091 NonNull.class, null, inheritFrom);
1092
1093 // onConstructed(); // You can define this method to get a callback
1094 }
1095
1096 @DataClass.Generated.Member
1097 public static final @NonNull Parcelable.Creator<ParsedFeature> CREATOR
1098 = new Parcelable.Creator<ParsedFeature>() {
1099 @Override
1100 public ParsedFeature[] newArray(int size) {
1101 return new ParsedFeature[size];
1102 }
1103
1104 @Override
1105 public ParsedFeature createFromParcel(@NonNull Parcel in) {
1106 return new ParsedFeature(in);
1107 }
1108 };
1109
1110 /*@DataClass.Generated(
1111 time = 1576783172965L,
1112 codegenVersion = "1.0.14",
1113 sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ComponentParseUtils.java",
1114 inputSignatures = "public final @android.annotation.NonNull java.lang.String id\npublic final @android.annotation.StringRes int label\npublic final @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static boolean isCombinationValid(java.util.List<android.content.pm.parsing.ParsedFeature>)\nclass ParsedFeature extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass")
1115 */
1116 @Deprecated
1117 private void __metadata() {}
1118
1119
1120 //@formatter:on
1121 // End of generated code
1122
1123 }
1124
Winson14ff7172019-10-23 10:42:27 -07001125 public static class ParsedPermission extends ParsedComponent<ParsedIntentInfo> {
1126
1127 public String backgroundPermission;
1128 private String group;
1129 public int requestRes;
1130 public int protectionLevel;
1131 public boolean tree;
1132
1133 public ParsedPermissionGroup parsedPermissionGroup;
1134
1135 public void setName(String className) {
1136 this.className = className;
1137 }
1138
1139 public void setGroup(String group) {
1140 this.group = TextUtils.safeIntern(group);
1141 }
1142
1143 public String getGroup() {
1144 return group;
1145 }
1146
1147 public boolean isRuntime() {
Winson6571c8a2019-10-23 17:00:42 -07001148 return getProtection() == PermissionInfo.PROTECTION_DANGEROUS;
Winson14ff7172019-10-23 10:42:27 -07001149 }
1150
1151 public boolean isAppOp() {
1152 return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0;
1153 }
1154
1155 @PermissionInfo.Protection
1156 public int getProtection() {
1157 return protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
1158 }
1159
1160 public int getProtectionFlags() {
1161 return protectionLevel & ~PermissionInfo.PROTECTION_MASK_BASE;
1162 }
1163
1164 public int calculateFootprint() {
1165 int size = getName().length();
1166 if (nonLocalizedLabel != null) {
1167 size += nonLocalizedLabel.length();
1168 }
1169 return size;
1170 }
1171
1172 public ParsedPermission() {
1173 }
1174
1175 public ParsedPermission(ParsedPermission other) {
1176 // TODO(b/135203078): Better way to copy this? Maybe refactor to the point where copy
1177 // isn't needed.
1178 this.className = other.className;
1179 this.icon = other.icon;
1180 this.labelRes = other.labelRes;
1181 this.nonLocalizedLabel = other.nonLocalizedLabel;
1182 this.logo = other.logo;
1183 this.banner = other.banner;
1184 this.descriptionRes = other.descriptionRes;
1185 this.enabled = other.enabled;
1186 this.directBootAware = other.directBootAware;
1187 this.flags = other.flags;
1188 this.setSplitName(other.getSplitName());
1189 this.setPackageName(other.getPackageName());
1190
1191 this.intents.addAll(other.intents);
1192
1193 if (other.metaData != null) {
1194 this.metaData = new Bundle();
1195 this.metaData.putAll(other.metaData);
1196 }
1197
1198 this.backgroundPermission = other.backgroundPermission;
1199 this.setGroup(other.group);
1200 this.requestRes = other.requestRes;
1201 this.protectionLevel = other.protectionLevel;
1202 this.tree = other.tree;
1203
1204 this.parsedPermissionGroup = other.parsedPermissionGroup;
1205 }
1206
1207 @Override
1208 public int describeContents() {
1209 return 0;
1210 }
1211
1212 @Override
1213 public void writeToParcel(Parcel dest, int flags) {
1214 super.writeToParcel(dest, flags);
1215 dest.writeString(this.backgroundPermission);
1216 dest.writeString(this.group);
1217 dest.writeInt(this.requestRes);
1218 dest.writeInt(this.protectionLevel);
1219 dest.writeBoolean(this.tree);
1220 dest.writeParcelable(this.parsedPermissionGroup, flags);
1221 }
1222
1223 protected ParsedPermission(Parcel in) {
1224 super(in);
1225 // We use the boot classloader for all classes that we load.
1226 final ClassLoader boot = Object.class.getClassLoader();
1227 this.backgroundPermission = in.readString();
1228 this.group = TextUtils.safeIntern(in.readString());
1229 this.requestRes = in.readInt();
1230 this.protectionLevel = in.readInt();
1231 this.tree = in.readBoolean();
1232 this.parsedPermissionGroup = in.readParcelable(boot);
1233 }
1234
1235 public static final Creator<ParsedPermission> CREATOR = new Creator<ParsedPermission>() {
1236 @Override
1237 public ParsedPermission createFromParcel(Parcel source) {
1238 return new ParsedPermission(source);
1239 }
1240
1241 @Override
1242 public ParsedPermission[] newArray(int size) {
1243 return new ParsedPermission[size];
1244 }
1245 };
1246 }
1247
1248 public static class ParsedPermissionGroup extends ParsedComponent<ParsedIntentInfo> {
1249
1250 public int requestDetailResourceId;
1251 public int backgroundRequestResourceId;
1252 public int backgroundRequestDetailResourceId;
1253
1254 public int requestRes;
1255 public int priority;
1256
1257 @Override
1258 public int describeContents() {
1259 return 0;
1260 }
1261
1262 @Override
1263 public void writeToParcel(Parcel dest, int flags) {
1264 super.writeToParcel(dest, flags);
1265 dest.writeInt(this.requestDetailResourceId);
1266 dest.writeInt(this.backgroundRequestResourceId);
1267 dest.writeInt(this.backgroundRequestDetailResourceId);
1268 dest.writeInt(this.requestRes);
1269 dest.writeInt(this.priority);
1270 }
1271
1272 public ParsedPermissionGroup() {
1273 }
1274
1275 protected ParsedPermissionGroup(Parcel in) {
1276 super(in);
1277 this.requestDetailResourceId = in.readInt();
1278 this.backgroundRequestResourceId = in.readInt();
1279 this.backgroundRequestDetailResourceId = in.readInt();
1280 this.requestRes = in.readInt();
1281 this.priority = in.readInt();
1282 }
1283
1284 public static final Creator<ParsedPermissionGroup> CREATOR =
1285 new Creator<ParsedPermissionGroup>() {
1286 @Override
1287 public ParsedPermissionGroup createFromParcel(Parcel source) {
1288 return new ParsedPermissionGroup(source);
1289 }
1290
1291 @Override
1292 public ParsedPermissionGroup[] newArray(int size) {
1293 return new ParsedPermissionGroup[size];
1294 }
1295 };
1296 }
1297
1298 public static class ParsedInstrumentation extends ParsedComponent<ParsedIntentInfo> {
1299
1300 private String targetPackage;
1301 private String targetProcesses;
1302 public boolean handleProfiling;
1303 public boolean functionalTest;
1304
Winson14ff7172019-10-23 10:42:27 -07001305 public ParsedInstrumentation() {
1306 }
1307
1308 public void setTargetPackage(String targetPackage) {
1309 this.targetPackage = TextUtils.safeIntern(targetPackage);
1310 }
1311
1312 public String getTargetPackage() {
1313 return targetPackage;
1314 }
1315
1316 public void setTargetProcesses(String targetProcesses) {
1317 this.targetProcesses = TextUtils.safeIntern(targetProcesses);
1318 }
1319
1320 public String getTargetProcesses() {
1321 return targetProcesses;
1322 }
1323
1324 @Override
1325 public int describeContents() {
1326 return 0;
1327 }
1328
1329 @Override
1330 public void writeToParcel(Parcel dest, int flags) {
1331 super.writeToParcel(dest, flags);
1332 dest.writeString(this.targetPackage);
1333 dest.writeString(this.targetProcesses);
1334 dest.writeBoolean(this.handleProfiling);
1335 dest.writeBoolean(this.functionalTest);
Winson14ff7172019-10-23 10:42:27 -07001336 }
1337
1338 protected ParsedInstrumentation(Parcel in) {
1339 super(in);
Winson14ff7172019-10-23 10:42:27 -07001340 this.targetPackage = TextUtils.safeIntern(in.readString());
1341 this.targetProcesses = TextUtils.safeIntern(in.readString());
1342 this.handleProfiling = in.readByte() != 0;
1343 this.functionalTest = in.readByte() != 0;
Winson14ff7172019-10-23 10:42:27 -07001344 }
1345
1346 public static final Creator<ParsedInstrumentation> CREATOR =
1347 new Creator<ParsedInstrumentation>() {
1348 @Override
1349 public ParsedInstrumentation createFromParcel(Parcel source) {
1350 return new ParsedInstrumentation(source);
1351 }
1352
1353 @Override
1354 public ParsedInstrumentation[] newArray(int size) {
1355 return new ParsedInstrumentation[size];
1356 }
1357 };
1358 }
1359
1360 public static ParsedActivity parseActivity(
1361 String[] separateProcesses,
1362 ParsingPackage parsingPackage,
1363 Resources res,
1364 XmlResourceParser parser, int flags, String[] outError,
1365 boolean receiver, boolean hardwareAccelerated)
1366 throws XmlPullParserException, IOException {
1367
1368 TypedArray sa = null;
1369 boolean visibleToEphemeral;
1370 boolean setExported;
1371
1372 int targetSdkVersion = parsingPackage.getTargetSdkVersion();
1373 String packageName = parsingPackage.getPackageName();
1374 String packageProcessName = parsingPackage.getProcessName();
1375 ParsedActivity result = new ParsedActivity();
1376
1377 try {
1378 sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
1379
1380 String tag = receiver ? "<receiver>" : "<activity>";
1381
1382 String name = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_name, 0);
1383 if (name == null) {
1384 outError[0] = tag + " does not specify android:name";
1385 return null;
1386 } else {
1387 String className = ApkParseUtils.buildClassName(packageName, name);
1388 if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
1389 outError[0] = tag + " invalid android:name";
1390 return null;
1391 } else if (className == null) {
1392 outError[0] = "Empty class name in package " + packageName;
1393 return null;
1394 }
1395
1396 result.className = className;
1397 }
1398
1399 int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
1400 R.styleable.AndroidManifestActivity_roundIcon, 0) : 0;
1401 if (roundIconVal != 0) {
1402 result.icon = roundIconVal;
1403 result.nonLocalizedLabel = null;
1404 } else {
1405 int iconVal = sa.getResourceId(R.styleable.AndroidManifestActivity_icon, 0);
1406 if (iconVal != 0) {
1407 result.icon = iconVal;
1408 result.nonLocalizedLabel = null;
1409 }
1410 }
1411
1412 int logoVal = sa.getResourceId(R.styleable.AndroidManifestActivity_logo, 0);
1413 if (logoVal != 0) {
1414 result.logo = logoVal;
1415 }
1416
1417 int bannerVal = sa.getResourceId(R.styleable.AndroidManifestActivity_banner, 0);
1418 if (bannerVal != 0) {
1419 result.banner = bannerVal;
1420 }
1421
1422 TypedValue v = sa.peekValue(R.styleable.AndroidManifestActivity_label);
1423 if (v != null && (result.labelRes = v.resourceId) == 0) {
1424 result.nonLocalizedLabel = v.coerceToString();
1425 }
1426
1427 result.setPackageNameInternal(packageName);
1428
1429 CharSequence pname;
1430 if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
1431 pname = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_process,
1432 Configuration.NATIVE_CONFIG_VERSION);
1433 } else {
1434 // Some older apps have been seen to use a resource reference
1435 // here that on older builds was ignored (with a warning). We
1436 // need to continue to do this for them so they don't break.
1437 pname = sa.getNonResourceString(R.styleable.AndroidManifestActivity_process);
1438 }
1439
1440 result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName,
1441 packageProcessName, pname,
1442 flags, separateProcesses, outError));
1443
1444 result.descriptionRes = sa.getResourceId(
1445 R.styleable.AndroidManifestActivity_description, 0);
1446
1447 result.enabled = sa.getBoolean(R.styleable.AndroidManifestActivity_enabled, true);
1448
1449 setExported = sa.hasValue(R.styleable.AndroidManifestActivity_exported);
1450 if (setExported) {
1451 result.exported = sa.getBoolean(R.styleable.AndroidManifestActivity_exported,
1452 false);
1453 }
1454
1455 result.theme = sa.getResourceId(R.styleable.AndroidManifestActivity_theme, 0);
1456
1457 result.uiOptions = sa.getInt(R.styleable.AndroidManifestActivity_uiOptions,
1458 parsingPackage.getUiOptions());
1459
1460 String parentName = sa.getNonConfigurationString(
1461 R.styleable.AndroidManifestActivity_parentActivityName,
1462 Configuration.NATIVE_CONFIG_VERSION);
1463 if (parentName != null) {
1464 String parentClassName = ApkParseUtils.buildClassName(packageName, parentName);
1465 if (parentClassName == null) {
1466 Log.e(TAG,
1467 "Activity " + result.className
1468 + " specified invalid parentActivityName " +
1469 parentName);
1470 } else {
1471 result.parentActivityName = parentClassName;
1472 }
1473 }
1474
1475 String str;
1476 str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0);
1477 if (str == null) {
1478 result.setPermission(parsingPackage.getPermission());
1479 } else {
1480 result.setPermission(str);
1481 }
1482
1483 str = sa.getNonConfigurationString(
1484 R.styleable.AndroidManifestActivity_taskAffinity,
1485 Configuration.NATIVE_CONFIG_VERSION);
1486 result.taskAffinity = PackageParser.buildTaskAffinityName(
1487 packageName,
1488 parsingPackage.getTaskAffinity(), str, outError);
1489
1490 result.setSplitName(
1491 sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_splitName, 0));
1492
1493 result.flags = 0;
1494 if (sa.getBoolean(
1495 R.styleable.AndroidManifestActivity_multiprocess, false)) {
1496 result.flags |= ActivityInfo.FLAG_MULTIPROCESS;
1497 }
1498
1499 if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnTaskLaunch, false)) {
1500 result.flags |= ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH;
1501 }
1502
1503 if (sa.getBoolean(R.styleable.AndroidManifestActivity_clearTaskOnLaunch, false)) {
1504 result.flags |= ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH;
1505 }
1506
1507 if (sa.getBoolean(R.styleable.AndroidManifestActivity_noHistory, false)) {
1508 result.flags |= ActivityInfo.FLAG_NO_HISTORY;
1509 }
1510
1511 if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysRetainTaskState, false)) {
1512 result.flags |= ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE;
1513 }
1514
1515 if (sa.getBoolean(R.styleable.AndroidManifestActivity_stateNotNeeded, false)) {
1516 result.flags |= ActivityInfo.FLAG_STATE_NOT_NEEDED;
1517 }
1518
1519 if (sa.getBoolean(R.styleable.AndroidManifestActivity_excludeFromRecents, false)) {
1520 result.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
1521 }
1522
1523 if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowTaskReparenting,
1524 (parsingPackage.getFlags() & ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING)
1525 != 0)) {
1526 result.flags |= ActivityInfo.FLAG_ALLOW_TASK_REPARENTING;
1527 }
1528
1529 if (sa.getBoolean(R.styleable.AndroidManifestActivity_finishOnCloseSystemDialogs,
1530 false)) {
1531 result.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
1532 }
1533
1534 if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false)
1535 || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) {
1536 result.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
1537 }
1538
1539 if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) {
1540 result.flags |= ActivityInfo.FLAG_IMMERSIVE;
1541 }
1542
1543 if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) {
1544 result.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY;
1545 }
1546
1547 boolean directBootAware;
1548
1549 if (!receiver) {
1550 if (sa.getBoolean(R.styleable.AndroidManifestActivity_hardwareAccelerated,
1551 hardwareAccelerated)) {
1552 result.flags |= ActivityInfo.FLAG_HARDWARE_ACCELERATED;
1553 }
1554
1555 result.launchMode = sa.getInt(
1556 R.styleable.AndroidManifestActivity_launchMode,
1557 ActivityInfo.LAUNCH_MULTIPLE);
1558 result.documentLaunchMode = sa.getInt(
1559 R.styleable.AndroidManifestActivity_documentLaunchMode,
1560 ActivityInfo.DOCUMENT_LAUNCH_NONE);
1561 result.maxRecents = sa.getInt(
1562 R.styleable.AndroidManifestActivity_maxRecents,
1563 ActivityTaskManager.getDefaultAppRecentsLimitStatic());
1564 result.configChanges = PackageParser.getActivityConfigChanges(
1565 sa.getInt(R.styleable.AndroidManifestActivity_configChanges, 0),
1566 sa.getInt(R.styleable.AndroidManifestActivity_recreateOnConfigChanges, 0));
1567 result.softInputMode = sa.getInt(
1568 R.styleable.AndroidManifestActivity_windowSoftInputMode, 0);
1569
1570 result.persistableMode = sa.getInteger(
1571 R.styleable.AndroidManifestActivity_persistableMode,
1572 ActivityInfo.PERSIST_ROOT_ONLY);
1573
1574 if (sa.getBoolean(R.styleable.AndroidManifestActivity_allowEmbedded, false)) {
1575 result.flags |= ActivityInfo.FLAG_ALLOW_EMBEDDED;
1576 }
1577
1578 if (sa.getBoolean(R.styleable.AndroidManifestActivity_autoRemoveFromRecents,
1579 false)) {
1580 result.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
1581 }
1582
1583 if (sa.getBoolean(R.styleable.AndroidManifestActivity_relinquishTaskIdentity,
1584 false)) {
1585 result.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
1586 }
1587
1588 if (sa.getBoolean(R.styleable.AndroidManifestActivity_resumeWhilePausing, false)) {
1589 result.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
1590 }
1591
1592 int screenOrientation = sa.getInt(
1593 R.styleable.AndroidManifestActivity_screenOrientation,
1594 SCREEN_ORIENTATION_UNSPECIFIED);
1595 result.screenOrientation = screenOrientation;
1596
1597 int resizeMode = getActivityResizeMode(parsingPackage, sa, screenOrientation);
1598 result.resizeMode = resizeMode;
1599
1600 if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
1601 false)) {
1602 result.flags |= FLAG_SUPPORTS_PICTURE_IN_PICTURE;
1603 }
1604
1605 if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
1606 result.flags |= FLAG_ALWAYS_FOCUSABLE;
1607 }
1608
1609 if (sa.hasValue(R.styleable.AndroidManifestActivity_maxAspectRatio)
1610 && sa.getType(R.styleable.AndroidManifestActivity_maxAspectRatio)
1611 == TypedValue.TYPE_FLOAT) {
1612 result.setMaxAspectRatio(resizeMode,
1613 sa.getFloat(R.styleable.AndroidManifestActivity_maxAspectRatio,
1614 0 /*default*/));
1615 }
1616
1617 if (sa.hasValue(R.styleable.AndroidManifestActivity_minAspectRatio)
1618 && sa.getType(R.styleable.AndroidManifestActivity_minAspectRatio)
1619 == TypedValue.TYPE_FLOAT) {
1620 result.setMinAspectRatio(resizeMode,
1621 sa.getFloat(R.styleable.AndroidManifestActivity_minAspectRatio,
1622 0 /*default*/));
1623 }
1624
1625 result.lockTaskLaunchMode =
1626 sa.getInt(R.styleable.AndroidManifestActivity_lockTaskMode, 0);
1627
1628 directBootAware = sa.getBoolean(
1629 R.styleable.AndroidManifestActivity_directBootAware,
1630 false);
1631
1632 result.requestedVrComponent =
1633 sa.getString(R.styleable.AndroidManifestActivity_enableVrMode);
1634
1635 result.rotationAnimation =
1636 sa.getInt(R.styleable.AndroidManifestActivity_rotationAnimation,
1637 ROTATION_ANIMATION_UNSPECIFIED);
1638
1639 result.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode,
1640 ActivityInfo.COLOR_MODE_DEFAULT);
1641
1642 if (sa.getBoolean(R.styleable.AndroidManifestActivity_showWhenLocked, false)) {
1643 result.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
1644 }
1645
1646 if (sa.getBoolean(R.styleable.AndroidManifestActivity_turnScreenOn, false)) {
1647 result.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON;
1648 }
1649
1650 if (sa.getBoolean(R.styleable.AndroidManifestActivity_inheritShowWhenLocked,
1651 false)) {
1652 result.privateFlags |= ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED;
1653 }
1654 } else {
1655 result.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
1656 result.configChanges = 0;
1657
1658 if (sa.getBoolean(R.styleable.AndroidManifestActivity_singleUser, false)) {
1659 result.flags |= ActivityInfo.FLAG_SINGLE_USER;
1660 }
1661 directBootAware = sa.getBoolean(
1662 R.styleable.AndroidManifestActivity_directBootAware,
1663 false);
1664 }
1665
1666 result.directBootAware = directBootAware;
1667
1668 if (directBootAware) {
1669 parsingPackage.setPartiallyDirectBootAware(true);
1670 }
1671
1672 // can't make this final; we may set it later via meta-data
1673 visibleToEphemeral = sa.getBoolean(
1674 R.styleable.AndroidManifestActivity_visibleToInstantApps, false);
1675 if (visibleToEphemeral) {
1676 result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
1677 parsingPackage.setVisibleToInstantApps(true);
1678 }
1679 } finally {
1680 if (sa != null) {
1681 sa.recycle();
1682 }
1683 }
1684
1685
1686 if (receiver && (parsingPackage.getPrivateFlags()
1687 & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
1688 // A heavy-weight application can not have receives in its main process
1689 if (result.getProcessName().equals(packageName)) {
1690 outError[0] = "Heavy-weight applications can not have receivers in main process";
1691 return null;
1692 }
1693 }
1694
1695 if (outError[0] != null) {
1696 return null;
1697 }
1698
1699 int outerDepth = parser.getDepth();
1700 int type;
1701 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1702 && (type != XmlPullParser.END_TAG
1703 || parser.getDepth() > outerDepth)) {
1704 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
1705 continue;
1706 }
1707
1708 if (parser.getName().equals("intent-filter")) {
1709 ParsedActivityIntentInfo intentInfo = new ParsedActivityIntentInfo(packageName,
1710 result.className);
1711 if (!parseIntentInfo(intentInfo, parsingPackage, res, parser,
1712 true /*allowGlobs*/,
1713 true /*allowAutoVerify*/, outError)) {
1714 return null;
1715 }
1716 if (intentInfo.countActions() == 0) {
1717 Slog.w(TAG, "No actions in intent filter at "
1718 + parsingPackage.getBaseCodePath() + " "
1719 + parser.getPositionDescription());
1720 } else {
1721 result.order = Math.max(intentInfo.getOrder(), result.order);
1722 result.addIntent(intentInfo);
1723 }
1724 // adjust activity flags when we implicitly expose it via a browsable filter
1725 final int visibility = visibleToEphemeral
1726 ? IntentFilter.VISIBILITY_EXPLICIT
1727 : !receiver && isImplicitlyExposedIntent(intentInfo)
1728 ? IntentFilter.VISIBILITY_IMPLICIT
1729 : IntentFilter.VISIBILITY_NONE;
1730 intentInfo.setVisibilityToInstantApp(visibility);
1731 if (intentInfo.isVisibleToInstantApp()) {
1732 result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
1733 }
1734 if (intentInfo.isImplicitlyVisibleToInstantApp()) {
1735 result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
1736 }
1737 if (PackageParser.LOG_UNSAFE_BROADCASTS && receiver
1738 && (targetSdkVersion >= Build.VERSION_CODES.O)) {
1739 for (int i = 0; i < intentInfo.countActions(); i++) {
1740 final String action = intentInfo.getAction(i);
1741 if (action == null || !action.startsWith("android.")) continue;
1742 if (!PackageParser.SAFE_BROADCASTS.contains(action)) {
1743 Slog.w(TAG, "Broadcast " + action + " may never be delivered to "
1744 + packageName + " as requested at: "
1745 + parser.getPositionDescription());
1746 }
1747 }
1748 }
1749 } else if (!receiver && parser.getName().equals("preferred")) {
1750 ParsedActivityIntentInfo intentInfo = new ParsedActivityIntentInfo(packageName,
1751 result.className);
1752 if (!parseIntentInfo(intentInfo, parsingPackage, res, parser,
1753 false /*allowGlobs*/,
1754 false /*allowAutoVerify*/, outError)) {
1755 return null;
1756 }
1757 // adjust activity flags when we implicitly expose it via a browsable filter
1758 final int visibility = visibleToEphemeral
1759 ? IntentFilter.VISIBILITY_EXPLICIT
1760 : !receiver && isImplicitlyExposedIntent(intentInfo)
1761 ? IntentFilter.VISIBILITY_IMPLICIT
1762 : IntentFilter.VISIBILITY_NONE;
1763 intentInfo.setVisibilityToInstantApp(visibility);
1764 if (intentInfo.isVisibleToInstantApp()) {
1765 result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
1766 }
1767 if (intentInfo.isImplicitlyVisibleToInstantApp()) {
1768 result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
1769 }
1770
1771 if (intentInfo.countActions() == 0) {
1772 Slog.w(TAG, "No actions in preferred at "
1773 + parsingPackage.getBaseCodePath() + " "
1774 + parser.getPositionDescription());
1775 } else {
1776 parsingPackage.addPreferredActivityFilter(intentInfo);
1777 }
1778 } else if (parser.getName().equals("meta-data")) {
1779 if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
1780 result.metaData,
1781 outError)) == null) {
1782 return null;
1783 }
1784 } else if (!receiver && parser.getName().equals("layout")) {
1785 result.windowLayout = parseLayout(res, parser);
1786 } else {
1787 if (!PackageParser.RIGID_PARSER) {
1788 Slog.w(TAG, "Problem in package " + parsingPackage.getBaseCodePath() + ":");
1789 if (receiver) {
1790 Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName()
1791 + " at " + parsingPackage.getBaseCodePath() + " "
1792 + parser.getPositionDescription());
1793 } else {
1794 Slog.w(TAG, "Unknown element under <activity>: " + parser.getName()
1795 + " at " + parsingPackage.getBaseCodePath() + " "
1796 + parser.getPositionDescription());
1797 }
1798 XmlUtils.skipCurrentTag(parser);
1799 continue;
1800 } else {
1801 if (receiver) {
1802 outError[0] = "Bad element under <receiver>: " + parser.getName();
1803 } else {
1804 outError[0] = "Bad element under <activity>: " + parser.getName();
1805 }
1806 return null;
1807 }
1808 }
1809 }
1810
1811 if (!setExported) {
1812 result.exported = result.intents.size() > 0;
1813 }
1814
1815 return result;
1816 }
1817
1818 public static boolean isImplicitlyExposedIntent(ParsedIntentInfo intentInfo) {
1819 return intentInfo.hasCategory(Intent.CATEGORY_BROWSABLE)
1820 || intentInfo.hasAction(Intent.ACTION_SEND)
1821 || intentInfo.hasAction(Intent.ACTION_SENDTO)
1822 || intentInfo.hasAction(Intent.ACTION_SEND_MULTIPLE);
1823 }
1824
1825 public static int getActivityResizeMode(
1826 ParsingPackage parsingPackage,
1827 TypedArray sa,
1828 int screenOrientation
1829 ) {
1830 int privateFlags = parsingPackage.getPrivateFlags();
1831 final boolean appExplicitDefault = (privateFlags
1832 & (ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE
1833 | ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE)) != 0;
1834
1835 if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity)
1836 || appExplicitDefault) {
1837 // Activity or app explicitly set if it is resizeable or not;
1838 final boolean appResizeable = (privateFlags
1839 & ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE) != 0;
1840 if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity,
1841 appResizeable)) {
1842 return ActivityInfo.RESIZE_MODE_RESIZEABLE;
1843 } else {
1844 return ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
1845 }
1846 }
1847
1848 if ((privateFlags
1849 & ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION)
1850 != 0) {
1851 // The activity or app didn't explicitly set the resizing option, however we want to
1852 // make it resize due to the sdk version it is targeting.
1853 return ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
1854 }
1855
1856 // resize preference isn't set and target sdk version doesn't support resizing apps by
1857 // default. For the app to be resizeable if it isn't fixed orientation or immersive.
1858 if (ActivityInfo.isFixedOrientationPortrait(screenOrientation)) {
1859 return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
1860 } else if (ActivityInfo.isFixedOrientationLandscape(screenOrientation)) {
1861 return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
1862 } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) {
1863 return ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
1864 } else {
1865 return ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
1866 }
1867 }
1868
1869 public static ParsedService parseService(
1870 String[] separateProcesses,
1871 ParsingPackage parsingPackage,
1872 Resources res,
1873 XmlResourceParser parser, int flags, String[] outError
1874 ) throws XmlPullParserException, IOException {
1875 TypedArray sa = null;
1876 boolean visibleToEphemeral;
1877 boolean setExported;
1878
1879 String packageName = parsingPackage.getPackageName();
1880 String packageProcessName = parsingPackage.getProcessName();
1881 ParsedService result = new ParsedService();
1882
1883 try {
1884 sa = res.obtainAttributes(parser,
1885 R.styleable.AndroidManifestService);
1886
1887 String name = sa.getNonConfigurationString(R.styleable.AndroidManifestService_name, 0);
1888 if (name == null) {
1889 outError[0] = "<service> does not specify android:name";
1890 return null;
1891 } else {
1892 String className = ApkParseUtils.buildClassName(packageName, name);
1893 if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
1894 outError[0] = "<service> invalid android:name";
1895 return null;
1896 } else if (className == null) {
1897 outError[0] = "Empty class name in package " + packageName;
1898 return null;
1899 }
1900
1901 result.className = className;
1902 }
1903
1904 int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
1905 R.styleable.AndroidManifestService_roundIcon, 0) : 0;
1906 if (roundIconVal != 0) {
1907 result.icon = roundIconVal;
1908 result.nonLocalizedLabel = null;
1909 } else {
1910 int iconVal = sa.getResourceId(R.styleable.AndroidManifestService_icon, 0);
1911 if (iconVal != 0) {
1912 result.icon = iconVal;
1913 result.nonLocalizedLabel = null;
1914 }
1915 }
1916
1917 int logoVal = sa.getResourceId(R.styleable.AndroidManifestService_logo, 0);
1918 if (logoVal != 0) {
1919 result.logo = logoVal;
1920 }
1921
1922 int bannerVal = sa.getResourceId(R.styleable.AndroidManifestService_banner, 0);
1923 if (bannerVal != 0) {
1924 result.banner = bannerVal;
1925 }
1926
1927 TypedValue v = sa.peekValue(R.styleable.AndroidManifestService_label);
1928 if (v != null && (result.labelRes = v.resourceId) == 0) {
1929 result.nonLocalizedLabel = v.coerceToString();
1930 }
1931
1932 result.setPackageNameInternal(packageName);
1933
1934 CharSequence pname;
1935 if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
1936 pname = sa.getNonConfigurationString(R.styleable.AndroidManifestService_process,
1937 Configuration.NATIVE_CONFIG_VERSION);
1938 } else {
1939 // Some older apps have been seen to use a resource reference
1940 // here that on older builds was ignored (with a warning). We
1941 // need to continue to do this for them so they don't break.
1942 pname = sa.getNonResourceString(R.styleable.AndroidManifestService_process);
1943 }
1944
1945 result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName,
1946 packageProcessName, pname,
1947 flags, separateProcesses, outError));
1948
1949 result.descriptionRes = sa.getResourceId(
1950 R.styleable.AndroidManifestService_description, 0);
1951
1952 result.enabled = sa.getBoolean(R.styleable.AndroidManifestService_enabled, true);
1953
1954 setExported = sa.hasValue(
1955 R.styleable.AndroidManifestService_exported);
1956 if (setExported) {
1957 result.exported = sa.getBoolean(
1958 R.styleable.AndroidManifestService_exported, false);
1959 }
1960
1961 String str = sa.getNonConfigurationString(
1962 R.styleable.AndroidManifestService_permission, 0);
1963 if (str == null) {
1964 result.setPermission(parsingPackage.getPermission());
1965 } else {
1966 result.setPermission(str);
1967 }
1968
1969 result.setSplitName(
1970 sa.getNonConfigurationString(R.styleable.AndroidManifestService_splitName, 0));
1971
1972 result.foregroundServiceType = sa.getInt(
1973 R.styleable.AndroidManifestService_foregroundServiceType,
1974 ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE);
1975
1976 result.flags = 0;
1977 if (sa.getBoolean(
1978 R.styleable.AndroidManifestService_stopWithTask,
1979 false)) {
1980 result.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
1981 }
1982 if (sa.getBoolean(
1983 R.styleable.AndroidManifestService_isolatedProcess,
1984 false)) {
1985 result.flags |= ServiceInfo.FLAG_ISOLATED_PROCESS;
1986 }
1987 if (sa.getBoolean(
1988 R.styleable.AndroidManifestService_externalService,
1989 false)) {
1990 result.flags |= ServiceInfo.FLAG_EXTERNAL_SERVICE;
1991 }
1992 if (sa.getBoolean(
1993 R.styleable.AndroidManifestService_useAppZygote,
1994 false)) {
1995 result.flags |= ServiceInfo.FLAG_USE_APP_ZYGOTE;
1996 }
1997 if (sa.getBoolean(
1998 R.styleable.AndroidManifestService_singleUser,
1999 false)) {
2000 result.flags |= ServiceInfo.FLAG_SINGLE_USER;
2001 }
2002
2003 result.directBootAware = sa.getBoolean(
2004 R.styleable.AndroidManifestService_directBootAware,
2005 false);
2006 if (result.directBootAware) {
2007 parsingPackage.setPartiallyDirectBootAware(true);
2008 }
2009
2010 visibleToEphemeral = sa.getBoolean(
2011 R.styleable.AndroidManifestService_visibleToInstantApps, false);
2012 if (visibleToEphemeral) {
2013 result.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
2014 parsingPackage.setVisibleToInstantApps(true);
2015 }
2016 } finally {
2017 if (sa != null) {
2018 sa.recycle();
2019 }
2020 }
2021
2022 if (parsingPackage.cantSaveState()) {
2023 // A heavy-weight application can not have services in its main process
2024 // We can do direct compare because we intern all strings.
2025 if (Objects.equals(result.getProcessName(), parsingPackage.getPackageName())) {
2026 outError[0] = "Heavy-weight applications can not have services in main process";
2027 return null;
2028 }
2029 }
2030
2031 int outerDepth = parser.getDepth();
2032 int type;
2033 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2034 && (type != XmlPullParser.END_TAG
2035 || parser.getDepth() > outerDepth)) {
2036 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2037 continue;
2038 }
2039
2040 if (parser.getName().equals("intent-filter")) {
2041 ParsedServiceIntentInfo intent = new ParsedServiceIntentInfo(packageName,
2042 result.className);
2043 if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/,
2044 false /*allowAutoVerify*/,
2045 outError)) {
2046 return null;
2047 }
2048 if (visibleToEphemeral) {
2049 intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
2050 result.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP;
2051 }
2052 result.order = Math.max(intent.getOrder(), result.order);
2053 result.intents.add(intent);
2054 } else if (parser.getName().equals("meta-data")) {
2055 if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
2056 result.metaData,
2057 outError)) == null) {
2058 return null;
2059 }
2060 } else {
2061 if (!PackageParser.RIGID_PARSER) {
2062 Slog.w(TAG, "Unknown element under <service>: "
2063 + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
2064 + parser.getPositionDescription());
2065 XmlUtils.skipCurrentTag(parser);
2066 continue;
2067 } else {
2068 outError[0] = "Bad element under <service>: " + parser.getName();
2069 return null;
2070 }
2071 }
2072 }
2073
2074 if (!setExported) {
2075 result.exported = result.intents.size() > 0;
2076 }
2077
2078 return result;
2079 }
2080
2081 public static ParsedProvider parseProvider(
2082 String[] separateProcesses,
2083 ParsingPackage parsingPackage,
2084 Resources res,
2085 XmlResourceParser parser, int flags, String[] outError)
2086 throws XmlPullParserException, IOException {
2087 TypedArray sa = null;
2088 String cpname;
2089 boolean visibleToEphemeral;
2090
2091 int targetSdkVersion = parsingPackage.getTargetSdkVersion();
2092 String packageName = parsingPackage.getPackageName();
2093 String packageProcessName = parsingPackage.getProcessName();
2094 ParsedProvider result = new ParsedProvider();
2095
2096 try {
2097 sa = res.obtainAttributes(parser,
2098 R.styleable.AndroidManifestProvider);
2099
2100 String name = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_name, 0);
2101 if (name == null) {
2102 outError[0] = "<provider> does not specify android:name";
2103 return null;
2104 } else {
2105 String className = ApkParseUtils.buildClassName(packageName, name);
2106 if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
2107 outError[0] = "<provider> invalid android:name";
2108 return null;
2109 } else if (className == null) {
2110 outError[0] = "Empty class name in package " + packageName;
2111 return null;
2112 }
2113
2114 result.className = className;
2115 }
2116
2117 int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
2118 R.styleable.AndroidManifestProvider_roundIcon, 0) : 0;
2119 if (roundIconVal != 0) {
2120 result.icon = roundIconVal;
2121 result.nonLocalizedLabel = null;
2122 } else {
2123 int iconVal = sa.getResourceId(R.styleable.AndroidManifestProvider_icon, 0);
2124 if (iconVal != 0) {
2125 result.icon = iconVal;
2126 result.nonLocalizedLabel = null;
2127 }
2128 }
2129
2130 int logoVal = sa.getResourceId(R.styleable.AndroidManifestProvider_logo, 0);
2131 if (logoVal != 0) {
2132 result.logo = logoVal;
2133 }
2134
2135 int bannerVal = sa.getResourceId(R.styleable.AndroidManifestProvider_banner, 0);
2136 if (bannerVal != 0) {
2137 result.banner = bannerVal;
2138 }
2139
2140 TypedValue v = sa.peekValue(R.styleable.AndroidManifestProvider_label);
2141 if (v != null && (result.labelRes = v.resourceId) == 0) {
2142 result.nonLocalizedLabel = v.coerceToString();
2143 }
2144
2145 result.setPackageNameInternal(packageName);
2146
2147 CharSequence pname;
2148 if (parsingPackage.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
2149 pname = sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_process,
2150 Configuration.NATIVE_CONFIG_VERSION);
2151 } else {
2152 // Some older apps have been seen to use a resource reference
2153 // here that on older builds was ignored (with a warning). We
2154 // need to continue to do this for them so they don't break.
2155 pname = sa.getNonResourceString(R.styleable.AndroidManifestProvider_process);
2156 }
2157
2158 result.setProcessName(packageProcessName, PackageParser.buildProcessName(packageName,
2159 packageProcessName, pname,
2160 flags, separateProcesses, outError));
2161
2162 result.descriptionRes = sa.getResourceId(
2163 R.styleable.AndroidManifestProvider_description, 0);
2164
2165 result.enabled = sa.getBoolean(R.styleable.AndroidManifestProvider_enabled, true);
2166
2167 boolean providerExportedDefault = false;
2168
2169 if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) {
2170 // For compatibility, applications targeting API level 16 or lower
2171 // should have their content providers exported by default, unless they
2172 // specify otherwise.
2173 providerExportedDefault = true;
2174 }
2175
2176 result.exported = sa.getBoolean(
2177 R.styleable.AndroidManifestProvider_exported,
2178 providerExportedDefault);
2179
2180 cpname = sa.getNonConfigurationString(
2181 R.styleable.AndroidManifestProvider_authorities, 0);
2182
2183 result.isSyncable = sa.getBoolean(
2184 R.styleable.AndroidManifestProvider_syncable,
2185 false);
2186
2187 String permission = sa.getNonConfigurationString(
2188 R.styleable.AndroidManifestProvider_permission, 0);
2189 String str = sa.getNonConfigurationString(
2190 R.styleable.AndroidManifestProvider_readPermission, 0);
2191 if (str == null) {
2192 str = permission;
2193 }
2194 if (str == null) {
2195 result.setReadPermission(parsingPackage.getPermission());
2196 } else {
2197 result.setReadPermission(str);
2198 }
2199 str = sa.getNonConfigurationString(
2200 R.styleable.AndroidManifestProvider_writePermission, 0);
2201 if (str == null) {
2202 str = permission;
2203 }
2204 if (str == null) {
2205 result.setWritePermission(parsingPackage.getPermission());
2206 } else {
2207 result.setWritePermission(str);
2208 }
2209
2210 result.grantUriPermissions = sa.getBoolean(
2211 R.styleable.AndroidManifestProvider_grantUriPermissions,
2212 false);
2213
2214 result.forceUriPermissions = sa.getBoolean(
2215 R.styleable.AndroidManifestProvider_forceUriPermissions,
2216 false);
2217
2218 result.multiProcess = sa.getBoolean(
2219 R.styleable.AndroidManifestProvider_multiprocess,
2220 false);
2221
2222 result.initOrder = sa.getInt(
2223 R.styleable.AndroidManifestProvider_initOrder,
2224 0);
2225
2226 result.setSplitName(
2227 sa.getNonConfigurationString(R.styleable.AndroidManifestProvider_splitName, 0));
2228
2229 result.flags = 0;
2230
2231 if (sa.getBoolean(
2232 R.styleable.AndroidManifestProvider_singleUser,
2233 false)) {
2234 result.flags |= ProviderInfo.FLAG_SINGLE_USER;
2235 }
2236
2237 result.directBootAware = sa.getBoolean(
2238 R.styleable.AndroidManifestProvider_directBootAware,
2239 false);
2240 if (result.directBootAware) {
2241 parsingPackage.setPartiallyDirectBootAware(true);
2242 }
2243
2244 visibleToEphemeral =
2245 sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToInstantApps, false);
2246 if (visibleToEphemeral) {
2247 result.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
2248 parsingPackage.setVisibleToInstantApps(true);
2249 }
2250 } finally {
2251 if (sa != null) {
2252 sa.recycle();
2253 }
2254 }
2255
2256 if ((parsingPackage.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE)
2257 != 0) {
2258 // A heavy-weight application can not have providers in its main process
2259 if (result.getProcessName().equals(packageName)) {
2260 outError[0] = "Heavy-weight applications can not have providers in main process";
2261 return null;
2262 }
2263 }
2264
2265 if (cpname == null) {
2266 outError[0] = "<provider> does not include authorities attribute";
2267 return null;
2268 }
2269 if (cpname.length() <= 0) {
2270 outError[0] = "<provider> has empty authorities attribute";
2271 return null;
2272 }
2273 result.setAuthority(cpname);
2274
2275 if (!parseProviderTags(parsingPackage, res, parser, visibleToEphemeral, result, outError)) {
2276 return null;
2277 }
2278
2279 return result;
2280 }
2281
2282 public static ParsedQueriesIntentInfo parsedParsedQueriesIntentInfo(
2283 ParsingPackage parsingPackage,
2284 Resources res,
2285 XmlResourceParser parser,
2286 String[] outError
2287 ) throws IOException, XmlPullParserException {
2288 ParsedQueriesIntentInfo intentInfo = new ParsedQueriesIntentInfo(
2289 parsingPackage.getPackageName(),
2290 null
2291 );
2292 if (!parseIntentInfo(
2293 intentInfo,
2294 parsingPackage,
2295 res,
2296 parser,
2297 true /*allowGlobs*/,
2298 true /*allowAutoVerify*/,
2299 outError
2300 )) {
2301 return null;
2302 }
2303 return intentInfo;
2304 }
2305
2306 private static boolean parseProviderTags(
2307 ParsingPackage parsingPackage,
2308 Resources res, XmlResourceParser parser,
2309 boolean visibleToEphemeral, ParsedProvider outInfo, String[] outError)
2310 throws XmlPullParserException, IOException {
2311 int outerDepth = parser.getDepth();
2312 int type;
2313 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2314 && (type != XmlPullParser.END_TAG
2315 || parser.getDepth() > outerDepth)) {
2316 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2317 continue;
2318 }
2319
2320 if (parser.getName().equals("intent-filter")) {
2321 ParsedProviderIntentInfo intent = new ParsedProviderIntentInfo(
2322 parsingPackage.getPackageName(), outInfo.className);
2323 if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/,
2324 false /*allowAutoVerify*/,
2325 outError)) {
2326 return false;
2327 }
2328 if (visibleToEphemeral) {
2329 intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT);
2330 outInfo.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP;
2331 }
2332 outInfo.order = Math.max(intent.getOrder(), outInfo.order);
2333 outInfo.intents.add(intent);
2334
2335 } else if (parser.getName().equals("meta-data")) {
2336 Bundle metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
2337 outInfo.metaData, outError);
2338 if (metaData == null) {
2339 return false;
2340 } else {
2341 outInfo.metaData = metaData;
2342 }
2343
2344 } else if (parser.getName().equals("grant-uri-permission")) {
2345 TypedArray sa = res.obtainAttributes(parser,
2346 R.styleable.AndroidManifestGrantUriPermission);
2347
2348 PatternMatcher pa = null;
2349
2350 String str = sa.getNonConfigurationString(
2351 R.styleable.AndroidManifestGrantUriPermission_path, 0);
2352 if (str != null) {
2353 pa = new PatternMatcher(str, PatternMatcher.PATTERN_LITERAL);
2354 }
2355
2356 str = sa.getNonConfigurationString(
2357 R.styleable.AndroidManifestGrantUriPermission_pathPrefix, 0);
2358 if (str != null) {
2359 pa = new PatternMatcher(str, PatternMatcher.PATTERN_PREFIX);
2360 }
2361
2362 str = sa.getNonConfigurationString(
2363 R.styleable.AndroidManifestGrantUriPermission_pathPattern, 0);
2364 if (str != null) {
2365 pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
2366 }
2367
2368 sa.recycle();
2369
2370 if (pa != null) {
2371 if (outInfo.uriPermissionPatterns == null) {
2372 outInfo.uriPermissionPatterns = new PatternMatcher[1];
2373 outInfo.uriPermissionPatterns[0] = pa;
2374 } else {
2375 final int N = outInfo.uriPermissionPatterns.length;
2376 PatternMatcher[] newp = new PatternMatcher[N + 1];
2377 System.arraycopy(outInfo.uriPermissionPatterns, 0, newp, 0, N);
2378 newp[N] = pa;
2379 outInfo.uriPermissionPatterns = newp;
2380 }
2381 outInfo.grantUriPermissions = true;
2382 } else {
2383 if (!PackageParser.RIGID_PARSER) {
2384 Slog.w(TAG, "Unknown element under <path-permission>: "
2385 + parser.getName() + " at " + parsingPackage.getBaseCodePath()
2386 + " "
2387 + parser.getPositionDescription());
2388 XmlUtils.skipCurrentTag(parser);
2389 continue;
2390 } else {
2391 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
2392 return false;
2393 }
2394 }
2395 XmlUtils.skipCurrentTag(parser);
2396
2397 } else if (parser.getName().equals("path-permission")) {
2398 TypedArray sa = res.obtainAttributes(parser,
2399 R.styleable.AndroidManifestPathPermission);
2400
2401 PathPermission pa = null;
2402
2403 String permission = sa.getNonConfigurationString(
2404 R.styleable.AndroidManifestPathPermission_permission, 0);
2405 String readPermission = sa.getNonConfigurationString(
2406 R.styleable.AndroidManifestPathPermission_readPermission, 0);
2407 if (readPermission == null) {
2408 readPermission = permission;
2409 }
2410 String writePermission = sa.getNonConfigurationString(
2411 R.styleable.AndroidManifestPathPermission_writePermission, 0);
2412 if (writePermission == null) {
2413 writePermission = permission;
2414 }
2415
2416 boolean havePerm = false;
2417 if (readPermission != null) {
2418 readPermission = readPermission.intern();
2419 havePerm = true;
2420 }
2421 if (writePermission != null) {
2422 writePermission = writePermission.intern();
2423 havePerm = true;
2424 }
2425
2426 if (!havePerm) {
2427 if (!PackageParser.RIGID_PARSER) {
2428 Slog.w(TAG, "No readPermission or writePermssion for <path-permission>: "
2429 + parser.getName() + " at " + parsingPackage.getBaseCodePath()
2430 + " "
2431 + parser.getPositionDescription());
2432 XmlUtils.skipCurrentTag(parser);
2433 continue;
2434 } else {
2435 outError[0] = "No readPermission or writePermssion for <path-permission>";
2436 return false;
2437 }
2438 }
2439
2440 String path = sa.getNonConfigurationString(
2441 R.styleable.AndroidManifestPathPermission_path, 0);
2442 if (path != null) {
2443 pa = new PathPermission(path,
2444 PatternMatcher.PATTERN_LITERAL, readPermission, writePermission);
2445 }
2446
2447 path = sa.getNonConfigurationString(
2448 R.styleable.AndroidManifestPathPermission_pathPrefix, 0);
2449 if (path != null) {
2450 pa = new PathPermission(path,
2451 PatternMatcher.PATTERN_PREFIX, readPermission, writePermission);
2452 }
2453
2454 path = sa.getNonConfigurationString(
2455 R.styleable.AndroidManifestPathPermission_pathPattern, 0);
2456 if (path != null) {
2457 pa = new PathPermission(path,
2458 PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission);
2459 }
2460
2461 path = sa.getNonConfigurationString(
2462 R.styleable.AndroidManifestPathPermission_pathAdvancedPattern, 0);
2463 if (path != null) {
2464 pa = new PathPermission(path,
2465 PatternMatcher.PATTERN_ADVANCED_GLOB, readPermission, writePermission);
2466 }
2467
2468 sa.recycle();
2469
2470 if (pa != null) {
2471 if (outInfo.pathPermissions == null) {
2472 outInfo.pathPermissions = new PathPermission[1];
2473 outInfo.pathPermissions[0] = pa;
2474 } else {
2475 final int N = outInfo.pathPermissions.length;
2476 PathPermission[] newp = new PathPermission[N + 1];
2477 System.arraycopy(outInfo.pathPermissions, 0, newp, 0, N);
2478 newp[N] = pa;
2479 outInfo.pathPermissions = newp;
2480 }
2481 } else {
2482 if (!PackageParser.RIGID_PARSER) {
2483 Slog.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>: "
2484 + parser.getName() + " at " + parsingPackage.getBaseCodePath()
2485 + " "
2486 + parser.getPositionDescription());
2487 XmlUtils.skipCurrentTag(parser);
2488 continue;
2489 }
2490 outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
2491 return false;
2492 }
2493 XmlUtils.skipCurrentTag(parser);
2494
2495 } else {
2496 if (!PackageParser.RIGID_PARSER) {
2497 Slog.w(TAG, "Unknown element under <provider>: "
2498 + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
2499 + parser.getPositionDescription());
2500 XmlUtils.skipCurrentTag(parser);
2501 continue;
2502 } else {
2503 outError[0] = "Bad element under <provider>: " + parser.getName();
2504 return false;
2505 }
2506 }
2507 }
2508 return true;
2509 }
2510
2511 public static ParsedActivity parseActivityAlias(
2512 ParsingPackage parsingPackage,
2513 Resources res,
2514 XmlResourceParser parser,
2515 String[] outError)
2516 throws XmlPullParserException, IOException {
2517 TypedArray sa = res.obtainAttributes(parser,
2518 R.styleable.AndroidManifestActivityAlias);
2519
2520 String targetActivity = sa.getNonConfigurationString(
2521 R.styleable.AndroidManifestActivityAlias_targetActivity,
2522 Configuration.NATIVE_CONFIG_VERSION);
2523 if (targetActivity == null) {
2524 outError[0] = "<activity-alias> does not specify android:targetActivity";
2525 sa.recycle();
2526 return null;
2527 }
2528
2529 String packageName = parsingPackage.getPackageName();
2530 targetActivity = ApkParseUtils.buildClassName(packageName, targetActivity);
2531 if (targetActivity == null) {
2532 outError[0] = "Empty class name in package " + packageName;
2533 sa.recycle();
2534 return null;
2535 }
2536
2537 ParsedActivity target = null;
2538
2539 List<ParsedActivity> activities = parsingPackage.getActivities();
2540 final int NA = activities.size();
2541 for (int i = 0; i < NA; i++) {
2542 ParsedActivity t = activities.get(i);
2543 if (targetActivity.equals(t.className)) {
2544 target = t;
2545 break;
2546 }
2547 }
2548
2549 if (target == null) {
2550 outError[0] = "<activity-alias> target activity " + targetActivity
2551 + " not found in manifest with activities = " + parsingPackage.getActivities()
2552 + ", parsedActivities = " + activities;
2553 sa.recycle();
2554 return null;
2555 }
2556
2557 ParsedActivity result = new ParsedActivity();
2558 result.setPackageNameInternal(target.getPackageName());
2559 result.targetActivity = targetActivity;
2560 result.configChanges = target.configChanges;
2561 result.flags = target.flags;
2562 result.privateFlags = target.privateFlags;
2563 result.icon = target.icon;
2564 result.logo = target.logo;
2565 result.banner = target.banner;
2566 result.labelRes = target.labelRes;
2567 result.nonLocalizedLabel = target.nonLocalizedLabel;
2568 result.launchMode = target.launchMode;
2569 result.lockTaskLaunchMode = target.lockTaskLaunchMode;
2570 result.descriptionRes = target.descriptionRes;
2571 result.screenOrientation = target.screenOrientation;
2572 result.taskAffinity = target.taskAffinity;
2573 result.theme = target.theme;
2574 result.softInputMode = target.softInputMode;
2575 result.uiOptions = target.uiOptions;
2576 result.parentActivityName = target.parentActivityName;
2577 result.maxRecents = target.maxRecents;
2578 result.windowLayout = target.windowLayout;
2579 result.resizeMode = target.resizeMode;
2580 result.maxAspectRatio = target.maxAspectRatio;
2581 result.hasMaxAspectRatio = target.hasMaxAspectRatio;
2582 result.minAspectRatio = target.minAspectRatio;
2583 result.hasMinAspectRatio = target.hasMinAspectRatio;
2584 result.requestedVrComponent = target.requestedVrComponent;
2585 result.directBootAware = target.directBootAware;
2586
2587 result.setProcessName(parsingPackage.getAppInfoProcessName(), target.getProcessName());
2588
2589 // Not all attributes from the target ParsedActivity are copied to the alias.
2590 // Careful when adding an attribute and determine whether or not it should be copied.
2591// result.enabled = target.enabled;
2592// result.exported = target.exported;
2593// result.permission = target.permission;
2594// result.splitName = target.splitName;
2595// result.documentLaunchMode = target.documentLaunchMode;
2596// result.persistableMode = target.persistableMode;
2597// result.rotationAnimation = target.rotationAnimation;
2598// result.colorMode = target.colorMode;
2599// result.intents.addAll(target.intents);
2600// result.order = target.order;
2601// result.metaData = target.metaData;
2602
2603 String name = sa.getNonConfigurationString(R.styleable.AndroidManifestActivityAlias_name,
2604 0);
2605 if (name == null) {
2606 outError[0] = "<activity-alias> does not specify android:name";
2607 return null;
2608 } else {
2609 String className = ApkParseUtils.buildClassName(packageName, name);
2610 if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
2611 outError[0] = "<activity-alias> invalid android:name";
2612 return null;
2613 } else if (className == null) {
2614 outError[0] = "Empty class name in package " + packageName;
2615 return null;
2616 }
2617
2618 result.className = className;
2619 }
2620
2621 int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
2622 R.styleable.AndroidManifestActivityAlias_roundIcon, 0) : 0;
2623 if (roundIconVal != 0) {
2624 result.icon = roundIconVal;
2625 result.nonLocalizedLabel = null;
2626 } else {
2627 int iconVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_icon, 0);
2628 if (iconVal != 0) {
2629 result.icon = iconVal;
2630 result.nonLocalizedLabel = null;
2631 }
2632 }
2633
2634 int logoVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_logo, 0);
2635 if (logoVal != 0) {
2636 result.logo = logoVal;
2637 }
2638
2639 int bannerVal = sa.getResourceId(R.styleable.AndroidManifestActivityAlias_banner, 0);
2640 if (bannerVal != 0) {
2641 result.banner = bannerVal;
2642 }
2643
2644 TypedValue v = sa.peekValue(R.styleable.AndroidManifestActivityAlias_label);
2645 if (v != null && (result.labelRes = v.resourceId) == 0) {
2646 result.nonLocalizedLabel = v.coerceToString();
2647 }
2648
2649 result.setPackageNameInternal(packageName);
2650
2651 result.descriptionRes = sa.getResourceId(
2652 R.styleable.AndroidManifestActivityAlias_description, 0);
2653
2654 result.enabled = sa.getBoolean(R.styleable.AndroidManifestActivityAlias_enabled, true);
2655
2656 final boolean setExported = sa.hasValue(
2657 R.styleable.AndroidManifestActivityAlias_exported);
2658 if (setExported) {
2659 result.exported = sa.getBoolean(
2660 R.styleable.AndroidManifestActivityAlias_exported, false);
2661 }
2662
2663 String str;
2664 str = sa.getNonConfigurationString(
2665 R.styleable.AndroidManifestActivityAlias_permission, 0);
2666 if (str != null) {
2667 result.setPermission(str);
2668 }
2669
2670 String parentName = sa.getNonConfigurationString(
2671 R.styleable.AndroidManifestActivityAlias_parentActivityName,
2672 Configuration.NATIVE_CONFIG_VERSION);
2673 if (parentName != null) {
2674 String parentClassName = ApkParseUtils.buildClassName(result.getPackageName(),
2675 parentName);
2676 if (parentClassName == null) {
2677 Log.e(TAG, "Activity alias " + result.className +
2678 " specified invalid parentActivityName " + parentName);
2679 outError[0] = null;
2680 } else {
2681 result.parentActivityName = parentClassName;
2682 }
2683 }
2684
2685 // TODO add visibleToInstantApps attribute to activity alias
2686 final boolean visibleToEphemeral =
2687 ((result.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0);
2688
2689 sa.recycle();
2690
2691 if (outError[0] != null) {
2692 return null;
2693 }
2694
2695 int outerDepth = parser.getDepth();
2696 int type;
2697 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2698 && (type != XmlPullParser.END_TAG
2699 || parser.getDepth() > outerDepth)) {
2700 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2701 continue;
2702 }
2703
2704 String tagName = parser.getName();
2705 if (tagName.equals("intent-filter")) {
2706 ParsedActivityIntentInfo intent = new ParsedActivityIntentInfo(packageName,
2707 result.className);
2708 if (!parseIntentInfo(intent, parsingPackage, res, parser, true /*allowGlobs*/,
2709 true /*allowAutoVerify*/, outError)) {
2710 return null;
2711 }
2712 if (intent.countActions() == 0) {
2713 Slog.w(TAG, "No actions in intent filter at "
2714 + parsingPackage.getBaseCodePath() + " "
2715 + parser.getPositionDescription());
2716 } else {
2717 result.order = Math.max(intent.getOrder(), result.order);
2718 result.addIntent(intent);
2719 }
2720 // adjust activity flags when we implicitly expose it via a browsable filter
2721 final int visibility = visibleToEphemeral
2722 ? IntentFilter.VISIBILITY_EXPLICIT
2723 : isImplicitlyExposedIntent(intent)
2724 ? IntentFilter.VISIBILITY_IMPLICIT
2725 : IntentFilter.VISIBILITY_NONE;
2726 intent.setVisibilityToInstantApp(visibility);
2727 if (intent.isVisibleToInstantApp()) {
2728 result.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
2729 }
2730 if (intent.isImplicitlyVisibleToInstantApp()) {
2731 result.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
2732 }
2733 } else if (tagName.equals("meta-data")) {
2734 if ((result.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
2735 result.metaData,
2736 outError)) == null) {
2737 return null;
2738 }
2739 } else {
2740 if (!PackageParser.RIGID_PARSER) {
2741 Slog.w(TAG, "Unknown element under <activity-alias>: " + tagName
2742 + " at " + parsingPackage.getBaseCodePath() + " "
2743 + parser.getPositionDescription());
2744 XmlUtils.skipCurrentTag(parser);
2745 continue;
2746 } else {
2747 outError[0] = "Bad element under <activity-alias>: " + tagName;
2748 return null;
2749 }
2750 }
2751 }
2752
2753 if (!setExported) {
2754 result.exported = result.intents.size() > 0;
2755 }
2756
2757 return result;
2758 }
2759
Philip P. Moltmann9046d822019-12-13 15:59:49 -08002760 public static ParsedFeature parseFeature(
2761 Resources res,
2762 XmlResourceParser parser,
2763 String[] outError
2764 ) throws IOException, XmlPullParserException {
2765 String featureId;
2766 int label;
2767 List<String> inheritFrom = null;
2768
2769 TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeature);
2770 if (sa == null) {
2771 outError[0] = "<feature> could not be parsed";
2772 return null;
2773 }
2774
2775 try {
2776 featureId = sa.getNonConfigurationString(R.styleable.AndroidManifestFeature_featureId,
2777 0);
2778 if (featureId == null) {
2779 outError[0] = "<featureId> does not specify android:featureId";
2780 return null;
2781 }
Philip P. Moltmanne52bd982020-01-02 15:24:01 -08002782 if (featureId.length() > ParsedFeature.MAX_FEATURE_ID_LEN) {
2783 outError[0] = "<featureId> is too long. Max length is "
2784 + ParsedFeature.MAX_FEATURE_ID_LEN;
2785 return null;
2786 }
Philip P. Moltmann9046d822019-12-13 15:59:49 -08002787
2788 label = sa.getResourceId(R.styleable.AndroidManifestFeature_label, 0);
2789 if (label == Resources.ID_NULL) {
2790 outError[0] = "<featureId> does not specify android:label";
2791 return null;
2792 }
2793 } finally {
2794 sa.recycle();
2795 }
2796
2797 int type;
2798 final int innerDepth = parser.getDepth();
2799 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
2800 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
2801 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
2802 continue;
2803 }
2804
2805 String tagName = parser.getName();
2806 if (tagName.equals("inherit-from")) {
2807 sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeatureInheritFrom);
2808 if (sa == null) {
2809 outError[0] = "<inherit-from> could not be parsed";
2810 return null;
2811 }
2812
2813 try {
2814 String inheritFromId = sa.getNonConfigurationString(
2815 R.styleable.AndroidManifestFeatureInheritFrom_featureId,0);
2816
2817 if (inheritFrom == null) {
2818 inheritFrom = new ArrayList<>();
2819 }
2820 inheritFrom.add(inheritFromId);
2821 } finally {
2822 sa.recycle();
2823 }
2824 } else {
2825 outError[0] = "Bad element under <feature>: " + tagName;
2826 return null;
2827 }
2828 }
2829
2830 if (inheritFrom == null) {
2831 inheritFrom = Collections.emptyList();
2832 } else {
2833 ((ArrayList) inheritFrom).trimToSize();
2834 }
2835
2836 return new ParsedFeature(featureId, label, inheritFrom);
2837 }
2838
Winson14ff7172019-10-23 10:42:27 -07002839 public static ParsedPermission parsePermission(
2840 ParsingPackage parsingPackage,
2841 Resources res,
2842 XmlResourceParser parser,
2843 String[] outError
2844 ) throws IOException, XmlPullParserException {
2845 TypedArray sa = null;
2846 String packageName = parsingPackage.getPackageName();
2847 ParsedPermission result = new ParsedPermission();
2848
2849 try {
2850 sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermission);
2851
2852 String name = sa.getNonConfigurationString(R.styleable.AndroidManifestPermission_name,
2853 0);
2854 if (name == null) {
2855 outError[0] = "<permission> does not specify android:name";
2856 return null;
2857 } else {
2858 String className = ApkParseUtils.buildClassName(packageName, name);
2859 if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
2860 outError[0] = "<permission> invalid android:name";
2861 return null;
2862 } else if (className == null) {
2863 outError[0] = "Empty class name in package " + packageName;
2864 return null;
2865 }
2866
2867 result.className = className;
2868 }
2869
2870 int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
2871 R.styleable.AndroidManifestPermission_roundIcon, 0) : 0;
2872 if (roundIconVal != 0) {
2873 result.icon = roundIconVal;
2874 result.nonLocalizedLabel = null;
2875 } else {
2876 int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermission_icon, 0);
2877 if (iconVal != 0) {
2878 result.icon = iconVal;
2879 result.nonLocalizedLabel = null;
2880 }
2881 }
2882
2883 int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermission_logo, 0);
2884 if (logoVal != 0) {
2885 result.logo = logoVal;
2886 }
2887
2888 int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermission_banner, 0);
2889 if (bannerVal != 0) {
2890 result.banner = bannerVal;
2891 }
2892
2893 TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermission_label);
2894 if (v != null && (result.labelRes = v.resourceId) == 0) {
2895 result.nonLocalizedLabel = v.coerceToString();
2896 }
2897
2898 result.setPackageNameInternal(packageName);
2899
2900 result.descriptionRes = sa.getResourceId(
2901 R.styleable.AndroidManifestPermission_description, 0);
2902
2903 if (sa.hasValue(
2904 R.styleable.AndroidManifestPermission_backgroundPermission)) {
2905 if ("android".equals(packageName)) {
2906 result.backgroundPermission = sa.getNonResourceString(
2907 R.styleable
2908 .AndroidManifestPermission_backgroundPermission);
2909 } else {
2910 Slog.w(TAG, packageName + " defines a background permission. Only the "
2911 + "'android' package can do that.");
2912 }
2913 }
2914
2915 // Note: don't allow this value to be a reference to a resource
2916 // that may change.
2917 result.setGroup(sa.getNonResourceString(
2918 R.styleable.AndroidManifestPermission_permissionGroup));
2919
2920 result.requestRes = sa.getResourceId(
2921 R.styleable.AndroidManifestPermission_request, 0);
2922
2923 result.protectionLevel = sa.getInt(
2924 R.styleable.AndroidManifestPermission_protectionLevel,
2925 PermissionInfo.PROTECTION_NORMAL);
2926
2927 result.flags = sa.getInt(
2928 R.styleable.AndroidManifestPermission_permissionFlags, 0);
2929
2930 // For now only platform runtime permissions can be restricted
2931 if (!result.isRuntime() || !"android".equals(result.getPackageName())) {
2932 result.flags &= ~PermissionInfo.FLAG_HARD_RESTRICTED;
2933 result.flags &= ~PermissionInfo.FLAG_SOFT_RESTRICTED;
2934 } else {
2935 // The platform does not get to specify conflicting permissions
2936 if ((result.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0
2937 && (result.flags & PermissionInfo.FLAG_SOFT_RESTRICTED) != 0) {
2938 throw new IllegalStateException("Permission cannot be both soft and hard"
2939 + " restricted: " + result.getName());
2940 }
2941 }
2942
2943 } finally {
2944 if (sa != null) {
2945 sa.recycle();
2946 }
2947 }
2948
2949 if (result.protectionLevel == -1) {
2950 outError[0] = "<permission> does not specify protectionLevel";
2951 return null;
2952 }
2953
2954 result.protectionLevel = PermissionInfo.fixProtectionLevel(result.protectionLevel);
2955
2956 if (result.getProtectionFlags() != 0) {
2957 if ((result.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) == 0
2958 && (result.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY)
2959 == 0
2960 && (result.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) !=
2961 PermissionInfo.PROTECTION_SIGNATURE) {
2962 outError[0] = "<permission> protectionLevel specifies a non-instant flag but is "
2963 + "not based on signature type";
2964 return null;
2965 }
2966 }
2967
2968 boolean success = parseAllMetaData(parsingPackage, res, parser,
2969 "<permission>", result, outError);
2970 if (!success || outError[0] != null) {
2971 return null;
2972 }
2973
2974 return result;
2975 }
2976
2977 public static ParsedPermission parsePermissionTree(
2978 ParsingPackage parsingPackage,
2979 Resources res,
2980 XmlResourceParser parser,
2981 String[] outError
2982 ) throws IOException, XmlPullParserException {
2983 TypedArray sa = null;
2984 String packageName = parsingPackage.getPackageName();
2985 ParsedPermission result = new ParsedPermission();
2986
2987 try {
2988 sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionTree);
2989
2990 String name = sa.getNonConfigurationString(
2991 R.styleable.AndroidManifestPermissionTree_name, 0);
2992 if (name == null) {
2993 outError[0] = "<permission-tree> does not specify android:name";
2994 return null;
2995 } else {
2996 String className = ApkParseUtils.buildClassName(packageName, name);
2997 if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
2998 outError[0] = "<permission-tree> invalid android:name";
2999 return null;
3000 } else if (className == null) {
3001 outError[0] = "Empty class name in package " + packageName;
3002 return null;
3003 }
3004
3005 result.className = className;
3006 }
3007
3008 int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
3009 R.styleable.AndroidManifestPermissionTree_roundIcon, 0) : 0;
3010 if (roundIconVal != 0) {
3011 result.icon = roundIconVal;
3012 result.nonLocalizedLabel = null;
3013 } else {
3014 int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_icon, 0);
3015 if (iconVal != 0) {
3016 result.icon = iconVal;
3017 result.nonLocalizedLabel = null;
3018 }
3019 }
3020
3021 int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_logo, 0);
3022 if (logoVal != 0) {
3023 result.logo = logoVal;
3024 }
3025
3026 int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermissionTree_banner, 0);
3027 if (bannerVal != 0) {
3028 result.banner = bannerVal;
3029 }
3030
3031 TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermissionTree_label);
3032 if (v != null && (result.labelRes = v.resourceId) == 0) {
3033 result.nonLocalizedLabel = v.coerceToString();
3034 }
3035
3036 result.setPackageNameInternal(packageName);
3037 } finally {
3038 if (sa != null) {
3039 sa.recycle();
3040 }
3041 }
3042
3043 int index = result.getName().indexOf('.');
3044 if (index > 0) {
3045 index = result.getName().indexOf('.', index + 1);
3046 }
3047 if (index < 0) {
3048 outError[0] =
3049 "<permission-tree> name has less than three segments: " + result.getName();
3050 return null;
3051 }
3052
3053 result.descriptionRes = 0;
3054 result.requestRes = 0;
3055 result.protectionLevel = PermissionInfo.PROTECTION_NORMAL;
3056 result.tree = true;
3057
3058 boolean success = parseAllMetaData(parsingPackage, res, parser,
3059 "<permission-tree>", result, outError);
3060 if (!success || outError[0] != null) {
3061 return null;
3062 }
3063
3064 return result;
3065 }
3066
3067 public static ParsedPermissionGroup parsePermissionGroup(
3068 ParsingPackage parsingPackage,
3069 Resources res,
3070 XmlResourceParser parser,
3071 String[] outError
3072 ) throws IOException, XmlPullParserException {
3073 TypedArray sa = null;
3074 String packageName = parsingPackage.getPackageName();
3075 ParsedPermissionGroup result = new ParsedPermissionGroup();
3076
3077 try {
3078 sa = res.obtainAttributes(parser, R.styleable.AndroidManifestPermissionGroup);
3079
3080 String name = sa.getNonConfigurationString(
3081 R.styleable.AndroidManifestPermissionGroup_name, 0);
3082 if (name == null) {
3083 outError[0] = "<permission> does not specify android:name";
3084 return null;
3085 } else {
3086 String className = ApkParseUtils.buildClassName(packageName, name);
3087 if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
3088 outError[0] = "<permission> invalid android:name";
3089 return null;
3090 } else if (className == null) {
3091 outError[0] = "Empty class name in package " + packageName;
3092 return null;
3093 }
3094
3095 result.className = className;
3096 }
3097
3098 int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
3099 R.styleable.AndroidManifestPermissionGroup_roundIcon, 0) : 0;
3100 if (roundIconVal != 0) {
3101 result.icon = roundIconVal;
3102 result.nonLocalizedLabel = null;
3103 } else {
3104 int iconVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_icon, 0);
3105 if (iconVal != 0) {
3106 result.icon = iconVal;
3107 result.nonLocalizedLabel = null;
3108 }
3109 }
3110
3111 int logoVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_logo, 0);
3112 if (logoVal != 0) {
3113 result.logo = logoVal;
3114 }
3115
3116 int bannerVal = sa.getResourceId(R.styleable.AndroidManifestPermissionGroup_banner, 0);
3117 if (bannerVal != 0) {
3118 result.banner = bannerVal;
3119 }
3120
3121 TypedValue v = sa.peekValue(R.styleable.AndroidManifestPermissionGroup_label);
3122 if (v != null && (result.labelRes = v.resourceId) == 0) {
3123 result.nonLocalizedLabel = v.coerceToString();
3124 }
3125
3126 result.setPackageNameInternal(packageName);
3127
3128 result.descriptionRes = sa.getResourceId(
3129 R.styleable.AndroidManifestPermissionGroup_description, 0);
3130
3131 result.requestDetailResourceId = sa.getResourceId(
3132 R.styleable.AndroidManifestPermissionGroup_requestDetail, 0);
3133 result.backgroundRequestResourceId = sa.getResourceId(
3134 R.styleable.AndroidManifestPermissionGroup_backgroundRequest,
3135 0);
3136 result.backgroundRequestDetailResourceId = sa.getResourceId(
3137 R.styleable
3138 .AndroidManifestPermissionGroup_backgroundRequestDetail, 0);
3139
3140 result.requestRes = sa.getResourceId(
3141 R.styleable.AndroidManifestPermissionGroup_request, 0);
3142 result.flags = sa.getInt(
3143 R.styleable.AndroidManifestPermissionGroup_permissionGroupFlags,
3144 0);
3145 result.priority = sa.getInt(
3146 R.styleable.AndroidManifestPermissionGroup_priority, 0);
3147
3148 } finally {
3149 if (sa != null) {
3150 sa.recycle();
3151 }
3152 }
3153
3154 boolean success = parseAllMetaData(parsingPackage, res, parser,
3155 "<permission-group>", result, outError);
3156 if (!success || outError[0] != null) {
3157 return null;
3158 }
3159
3160 return result;
3161 }
3162
3163 public static ParsedInstrumentation parseInstrumentation(
3164 ParsingPackage parsingPackage,
3165 Resources res,
3166 XmlResourceParser parser,
3167 String[] outError
3168 ) throws IOException, XmlPullParserException {
3169 TypedArray sa = null;
3170 String packageName = parsingPackage.getPackageName();
3171 ParsedInstrumentation result = new ParsedInstrumentation();
3172
3173 try {
3174 sa = res.obtainAttributes(parser, R.styleable.AndroidManifestInstrumentation);
3175
3176 // TODO(b/135203078): Re-share all of the configuration for this. ParseComponentArgs was
3177 // un-used for this, but can be adjusted and re-added to share all the initial result
3178 // parsing for icon/logo/name/etc in all of these parse methods.
3179 String name = sa.getNonConfigurationString(
3180 R.styleable.AndroidManifestInstrumentation_name, 0);
3181 if (name == null) {
3182 outError[0] = "<instrumentation> does not specify android:name";
3183 return null;
3184 } else {
3185 String className = ApkParseUtils.buildClassName(packageName, name);
3186 if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
3187 outError[0] = "<instrumentation> invalid android:name";
3188 return null;
3189 } else if (className == null) {
3190 outError[0] = "Empty class name in package " + packageName;
3191 return null;
3192 }
3193
3194 result.className = className;
3195 }
3196
3197 int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
3198 R.styleable.AndroidManifestInstrumentation_roundIcon, 0) : 0;
3199 if (roundIconVal != 0) {
3200 result.icon = roundIconVal;
3201 result.nonLocalizedLabel = null;
3202 } else {
3203 int iconVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_icon, 0);
3204 if (iconVal != 0) {
3205 result.icon = iconVal;
3206 result.nonLocalizedLabel = null;
3207 }
3208 }
3209
3210 int logoVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_logo, 0);
3211 if (logoVal != 0) {
3212 result.logo = logoVal;
3213 }
3214
3215 int bannerVal = sa.getResourceId(R.styleable.AndroidManifestInstrumentation_banner, 0);
3216 if (bannerVal != 0) {
3217 result.banner = bannerVal;
3218 }
3219
3220 TypedValue v = sa.peekValue(R.styleable.AndroidManifestInstrumentation_label);
3221 if (v != null && (result.labelRes = v.resourceId) == 0) {
3222 result.nonLocalizedLabel = v.coerceToString();
3223 }
3224
3225 result.setPackageNameInternal(packageName);
3226
3227 String str;
3228 // Note: don't allow this value to be a reference to a resource
3229 // that may change.
3230 str = sa.getNonResourceString(R.styleable.AndroidManifestInstrumentation_targetPackage);
3231 result.setTargetPackage(str);
3232
3233 str = sa.getNonResourceString(
3234 R.styleable.AndroidManifestInstrumentation_targetProcesses);
3235 result.setTargetProcesses(str);
3236 result.handleProfiling = sa.getBoolean(
3237 R.styleable.AndroidManifestInstrumentation_handleProfiling, false);
3238 result.functionalTest = sa.getBoolean(
3239 R.styleable.AndroidManifestInstrumentation_functionalTest, false);
3240
3241 } finally {
3242 if (sa != null) {
3243 sa.recycle();
3244 }
3245 }
3246
3247 boolean success = parseAllMetaData(parsingPackage, res, parser,
3248 "<instrumentation>", result, outError);
3249 if (!success || outError[0] != null) {
3250 return null;
3251 }
3252
3253 return result;
3254 }
3255
3256 public static ActivityInfo.WindowLayout parseLayout(Resources res, AttributeSet attrs) {
3257 TypedArray sw = res.obtainAttributes(attrs,
3258 R.styleable.AndroidManifestLayout);
3259 int width = -1;
3260 float widthFraction = -1f;
3261 int height = -1;
3262 float heightFraction = -1f;
3263 final int widthType = sw.getType(
3264 R.styleable.AndroidManifestLayout_defaultWidth);
3265 if (widthType == TypedValue.TYPE_FRACTION) {
3266 widthFraction = sw.getFraction(
3267 R.styleable.AndroidManifestLayout_defaultWidth,
3268 1, 1, -1);
3269 } else if (widthType == TypedValue.TYPE_DIMENSION) {
3270 width = sw.getDimensionPixelSize(
3271 R.styleable.AndroidManifestLayout_defaultWidth,
3272 -1);
3273 }
3274 final int heightType = sw.getType(
3275 R.styleable.AndroidManifestLayout_defaultHeight);
3276 if (heightType == TypedValue.TYPE_FRACTION) {
3277 heightFraction = sw.getFraction(
3278 R.styleable.AndroidManifestLayout_defaultHeight,
3279 1, 1, -1);
3280 } else if (heightType == TypedValue.TYPE_DIMENSION) {
3281 height = sw.getDimensionPixelSize(
3282 R.styleable.AndroidManifestLayout_defaultHeight,
3283 -1);
3284 }
3285 int gravity = sw.getInt(
3286 R.styleable.AndroidManifestLayout_gravity,
3287 Gravity.CENTER);
3288 int minWidth = sw.getDimensionPixelSize(
3289 R.styleable.AndroidManifestLayout_minWidth,
3290 -1);
3291 int minHeight = sw.getDimensionPixelSize(
3292 R.styleable.AndroidManifestLayout_minHeight,
3293 -1);
3294 sw.recycle();
3295 return new ActivityInfo.WindowLayout(width, widthFraction,
3296 height, heightFraction, gravity, minWidth, minHeight);
3297 }
3298
3299 public static boolean parseIntentInfo(
3300 ParsedIntentInfo intentInfo,
3301 ParsingPackage parsingPackage,
3302 Resources res, XmlResourceParser parser, boolean allowGlobs,
3303 boolean allowAutoVerify, String[] outError
3304 ) throws XmlPullParserException, IOException {
3305 TypedArray sa = res.obtainAttributes(parser,
3306 R.styleable.AndroidManifestIntentFilter);
3307
3308 int priority = sa.getInt(
3309 R.styleable.AndroidManifestIntentFilter_priority, 0);
3310 intentInfo.setPriority(priority);
3311
3312 int order = sa.getInt(
3313 R.styleable.AndroidManifestIntentFilter_order, 0);
3314 intentInfo.setOrder(order);
3315
3316 TypedValue v = sa.peekValue(
3317 R.styleable.AndroidManifestIntentFilter_label);
3318 if (v != null && (intentInfo.labelRes = v.resourceId) == 0) {
3319 intentInfo.nonLocalizedLabel = v.coerceToString();
3320 }
3321
3322 int roundIconVal = PackageParser.sUseRoundIcon ? sa.getResourceId(
3323 R.styleable.AndroidManifestIntentFilter_roundIcon, 0) : 0;
3324 if (roundIconVal != 0) {
3325 intentInfo.icon = roundIconVal;
3326 } else {
3327 intentInfo.icon = sa.getResourceId(
3328 R.styleable.AndroidManifestIntentFilter_icon, 0);
3329 }
3330
3331 if (allowAutoVerify) {
3332 intentInfo.setAutoVerify(sa.getBoolean(
3333 R.styleable.AndroidManifestIntentFilter_autoVerify,
3334 false));
3335 }
3336
3337 sa.recycle();
3338
3339 int outerDepth = parser.getDepth();
3340 int type;
3341 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3342 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
3343 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3344 continue;
3345 }
3346
3347 String nodeName = parser.getName();
3348 if (nodeName.equals("action")) {
3349 String value = parser.getAttributeValue(
3350 PackageParser.ANDROID_RESOURCES, "name");
3351 if (TextUtils.isEmpty(value)) {
3352 outError[0] = "No value supplied for <android:name>";
3353 return false;
3354 }
3355 XmlUtils.skipCurrentTag(parser);
3356
3357 intentInfo.addAction(value);
3358 } else if (nodeName.equals("category")) {
3359 String value = parser.getAttributeValue(
3360 PackageParser.ANDROID_RESOURCES, "name");
3361 if (TextUtils.isEmpty(value)) {
3362 outError[0] = "No value supplied for <android:name>";
3363 return false;
3364 }
3365 XmlUtils.skipCurrentTag(parser);
3366
3367 intentInfo.addCategory(value);
3368
3369 } else if (nodeName.equals("data")) {
3370 sa = res.obtainAttributes(parser,
3371 R.styleable.AndroidManifestData);
3372
3373 String str = sa.getNonConfigurationString(
3374 R.styleable.AndroidManifestData_mimeType, 0);
3375 if (str != null) {
3376 try {
3377 intentInfo.addRawDataType(str);
3378 } catch (IntentFilter.MalformedMimeTypeException e) {
3379 outError[0] = e.toString();
3380 sa.recycle();
3381 return false;
3382 }
3383 }
3384
3385 str = sa.getNonConfigurationString(
3386 R.styleable.AndroidManifestData_scheme, 0);
3387 if (str != null) {
3388 intentInfo.addDataScheme(str);
3389 }
3390
3391 str = sa.getNonConfigurationString(
3392 R.styleable.AndroidManifestData_ssp, 0);
3393 if (str != null) {
3394 intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_LITERAL);
3395 }
3396
3397 str = sa.getNonConfigurationString(
3398 R.styleable.AndroidManifestData_sspPrefix, 0);
3399 if (str != null) {
3400 intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_PREFIX);
3401 }
3402
3403 str = sa.getNonConfigurationString(
3404 R.styleable.AndroidManifestData_sspPattern, 0);
3405 if (str != null) {
3406 if (!allowGlobs) {
3407 outError[0] = "sspPattern not allowed here; ssp must be literal";
3408 return false;
3409 }
3410 intentInfo.addDataSchemeSpecificPart(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
3411 }
3412
3413 String host = sa.getNonConfigurationString(
3414 R.styleable.AndroidManifestData_host, 0);
3415 String port = sa.getNonConfigurationString(
3416 R.styleable.AndroidManifestData_port, 0);
3417 if (host != null) {
3418 intentInfo.addDataAuthority(host, port);
3419 }
3420
3421 str = sa.getNonConfigurationString(
3422 R.styleable.AndroidManifestData_path, 0);
3423 if (str != null) {
3424 intentInfo.addDataPath(str, PatternMatcher.PATTERN_LITERAL);
3425 }
3426
3427 str = sa.getNonConfigurationString(
3428 R.styleable.AndroidManifestData_pathPrefix, 0);
3429 if (str != null) {
3430 intentInfo.addDataPath(str, PatternMatcher.PATTERN_PREFIX);
3431 }
3432
3433 str = sa.getNonConfigurationString(
3434 R.styleable.AndroidManifestData_pathPattern, 0);
3435 if (str != null) {
3436 if (!allowGlobs) {
3437 outError[0] = "pathPattern not allowed here; path must be literal";
3438 return false;
3439 }
3440 intentInfo.addDataPath(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
3441 }
3442
3443 str = sa.getNonConfigurationString(
3444 R.styleable.AndroidManifestData_pathAdvancedPattern, 0);
3445 if (str != null) {
3446 if (!allowGlobs) {
3447 outError[0] = "pathAdvancedPattern not allowed here; path must be literal";
3448 return false;
3449 }
3450 intentInfo.addDataPath(str, PatternMatcher.PATTERN_ADVANCED_GLOB);
3451 }
3452
3453 sa.recycle();
3454 XmlUtils.skipCurrentTag(parser);
3455 } else if (!PackageParser.RIGID_PARSER) {
3456 Slog.w(TAG, "Unknown element under <intent-filter>: "
3457 + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
3458 + parser.getPositionDescription());
3459 XmlUtils.skipCurrentTag(parser);
3460 } else {
3461 outError[0] = "Bad element under <intent-filter>: " + parser.getName();
3462 return false;
3463 }
3464 }
3465
3466 intentInfo.hasDefault = intentInfo.hasCategory(Intent.CATEGORY_DEFAULT);
3467
3468 if (PackageParser.DEBUG_PARSER) {
3469 final StringBuilder cats = new StringBuilder("Intent d=");
3470 cats.append(intentInfo.hasDefault);
3471 cats.append(", cat=");
3472
3473 final Iterator<String> it = intentInfo.categoriesIterator();
3474 if (it != null) {
3475 while (it.hasNext()) {
3476 cats.append(' ');
3477 cats.append(it.next());
3478 }
3479 }
3480 Slog.d(TAG, cats.toString());
3481 }
3482
3483 return true;
3484 }
3485
3486 private static boolean parseAllMetaData(
3487 ParsingPackage parsingPackage,
3488 Resources res, XmlResourceParser parser, String tag,
3489 ParsedComponent outInfo,
3490 String[] outError
3491 ) throws XmlPullParserException, IOException {
3492 int outerDepth = parser.getDepth();
3493 int type;
3494 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
3495 && (type != XmlPullParser.END_TAG
3496 || parser.getDepth() > outerDepth)) {
3497 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
3498 continue;
3499 }
3500
3501 if (parser.getName().equals("meta-data")) {
3502 if ((outInfo.metaData = ApkParseUtils.parseMetaData(parsingPackage, res, parser,
3503 outInfo.metaData, outError)) == null) {
3504 return false;
3505 }
3506 } else {
3507 if (!PackageParser.RIGID_PARSER) {
3508 Slog.w(TAG, "Unknown element under " + tag + ": "
3509 + parser.getName() + " at " + parsingPackage.getBaseCodePath() + " "
3510 + parser.getPositionDescription());
3511 XmlUtils.skipCurrentTag(parser);
3512 continue;
3513 } else {
3514 outError[0] = "Bad element under " + tag + ": " + parser.getName();
3515 }
3516 }
3517 }
3518
3519 return true;
3520 }
3521
3522 public static boolean isImplicitlyExposedIntent(IntentFilter intent) {
3523 return intent.hasCategory(Intent.CATEGORY_BROWSABLE)
3524 || intent.hasAction(Intent.ACTION_SEND)
3525 || intent.hasAction(Intent.ACTION_SENDTO)
3526 || intent.hasAction(Intent.ACTION_SEND_MULTIPLE);
3527 }
3528}