1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.pm.pkg.component;
18 
19 import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.content.IntentFilter;
24 import android.content.pm.parsing.result.ParseInput;
25 import android.content.pm.parsing.result.ParseResult;
26 import android.content.res.Configuration;
27 import android.content.res.Resources;
28 import android.content.res.TypedArray;
29 import android.content.res.XmlResourceParser;
30 import android.os.Build;
31 import android.util.Slog;
32 
33 import com.android.internal.annotations.VisibleForTesting;
34 import com.android.internal.pm.pkg.parsing.ParsingPackage;
35 import com.android.internal.pm.pkg.parsing.ParsingUtils;
36 
37 import org.xmlpull.v1.XmlPullParserException;
38 
39 import java.io.IOException;
40 
41 /** @hide */
42 class ParsedMainComponentUtils {
43 
44     private static final String TAG = ParsingUtils.TAG;
45 
46     @NonNull
47     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
parseMainComponent( Component component, String tag, String[] separateProcesses, ParsingPackage pkg, TypedArray array, int flags, boolean useRoundIcon, @Nullable String defaultSplitName, @NonNull ParseInput input, int bannerAttr, int descriptionAttr, int directBootAwareAttr, int enabledAttr, int iconAttr, int labelAttr, int logoAttr, int nameAttr, int processAttr, int roundIconAttr, int splitNameAttr, int attributionTagsAttr)48     static <Component extends ParsedMainComponentImpl> ParseResult<Component> parseMainComponent(
49             Component component, String tag, String[] separateProcesses, ParsingPackage pkg,
50             TypedArray array, int flags, boolean useRoundIcon,  @Nullable String defaultSplitName,
51             @NonNull ParseInput input, int bannerAttr, int descriptionAttr, int directBootAwareAttr,
52             int enabledAttr, int iconAttr, int labelAttr, int logoAttr, int nameAttr,
53             int processAttr, int roundIconAttr, int splitNameAttr, int attributionTagsAttr) {
54         ParseResult<Component> result = ParsedComponentUtils.parseComponent(component, tag, pkg,
55                 array, useRoundIcon, input, bannerAttr, descriptionAttr, iconAttr, labelAttr,
56                 logoAttr, nameAttr, roundIconAttr);
57         if (result.isError()) {
58             return result;
59         }
60 
61         if (directBootAwareAttr != NOT_SET) {
62             component.setDirectBootAware(array.getBoolean(directBootAwareAttr, false));
63             if (component.isDirectBootAware()) {
64                 pkg.setPartiallyDirectBootAware(true);
65             }
66         }
67 
68         if (enabledAttr != NOT_SET) {
69             component.setEnabled(array.getBoolean(enabledAttr, true));
70         }
71 
72         if (processAttr != NOT_SET) {
73             CharSequence processName;
74             if (pkg.getTargetSdkVersion() >= Build.VERSION_CODES.FROYO) {
75                 processName = array.getNonConfigurationString(processAttr,
76                         Configuration.NATIVE_CONFIG_VERSION);
77             } else {
78                 // Some older apps have been seen to use a resource reference
79                 // here that on older builds was ignored (with a warning).  We
80                 // need to continue to do this for them so they don't break.
81                 processName = array.getNonResourceString(processAttr);
82             }
83 
84             // Backwards-compat, ignore error
85             ParseResult<String> processNameResult = ComponentParseUtils.buildProcessName(
86                     pkg.getPackageName(), pkg.getProcessName(), processName, flags,
87                     separateProcesses, input);
88             if (processNameResult.isError()) {
89                 return input.error(processNameResult);
90             }
91 
92             component.setProcessName(processNameResult.getResult());
93         }
94 
95         if (splitNameAttr != NOT_SET) {
96             component.setSplitName(array.getNonConfigurationString(splitNameAttr, 0));
97         }
98 
99         if (defaultSplitName != null && component.getSplitName() == null) {
100             component.setSplitName(defaultSplitName);
101         }
102 
103         if (attributionTagsAttr != NOT_SET) {
104             final String attributionTags = array.getNonConfigurationString(attributionTagsAttr, 0);
105             if (attributionTags != null) {
106                 component.setAttributionTags(attributionTags.split("\\|"));
107             }
108         }
109 
110         return input.success(component);
111     }
112 
parseIntentFilter( ParsedMainComponent mainComponent, ParsingPackage pkg, Resources resources, XmlResourceParser parser, boolean visibleToEphemeral, boolean allowGlobs, boolean allowAutoVerify, boolean allowImplicitEphemeralVisibility, boolean failOnNoActions, ParseInput input)113     static ParseResult<ParsedIntentInfoImpl> parseIntentFilter(
114             ParsedMainComponent mainComponent,
115             ParsingPackage pkg, Resources resources, XmlResourceParser parser,
116             boolean visibleToEphemeral, boolean allowGlobs, boolean allowAutoVerify,
117             boolean allowImplicitEphemeralVisibility, boolean failOnNoActions,
118             ParseInput input) throws IOException, XmlPullParserException {
119         ParseResult<ParsedIntentInfoImpl> intentResult = ParsedIntentInfoUtils.parseIntentInfo(
120                 mainComponent.getName(), pkg, resources, parser, allowGlobs,
121                 allowAutoVerify, input);
122         if (intentResult.isError()) {
123             return input.error(intentResult);
124         }
125 
126         ParsedIntentInfo intent = intentResult.getResult();
127         IntentFilter intentFilter = intent.getIntentFilter();
128         int actionCount = intentFilter.countActions();
129         if (actionCount == 0 && failOnNoActions) {
130             Slog.w(TAG, "No actions in " + parser.getName() + " at " + pkg.getBaseApkPath() + " "
131                     + parser.getPositionDescription());
132             // Backward-compat, do not actually fail
133             return input.success(null);
134         }
135 
136         int intentVisibility;
137         if (visibleToEphemeral) {
138             intentVisibility = IntentFilter.VISIBILITY_EXPLICIT;
139         } else if (allowImplicitEphemeralVisibility
140                 && ComponentParseUtils.isImplicitlyExposedIntent(intent)){
141             intentVisibility = IntentFilter.VISIBILITY_IMPLICIT;
142         } else {
143             intentVisibility = IntentFilter.VISIBILITY_NONE;
144         }
145         intentFilter.setVisibilityToInstantApp(intentVisibility);
146 
147         return input.success(intentResult.getResult());
148     }
149 
150 }
151